lancet: Clojure controlling Ant

98 views
Skip to first unread message

Stuart Halloway

unread,
Nov 6, 2008, 1:48:43 PM11/6/08
to clo...@googlegroups.com
Hi all,

I am playing around with using Clojure to control Ant, something along
the lines of Groovy's Gant. I don't know how far I will take this--
right now it is serving as a code example for the book.

Two questions:

(1) Anybody interested in seeing lancet carried forward into a real
project?

(2) Below is an example of lancet syntax (compare with Clojure's own
build.xml). Any big likes/dislikes?

Cheers,
Stuart

(project {:name "clojure" :default "jar"}

(properties :src "src"
:jsrc (i :src "/jvm")
:cljsrc (i :src "/clj")
:build "classes"
:clojure_jar "clojure.jar"
:bootclj (i :cljsrc "/clojure/boot.clj"))

(target {:name "test"}
(echo {:message "init target"}))

(target {:name "compile" :depends "init"
:description "Compile Java sources."}
(javac {:srcdir (i :jsrc) :destdir (i :build)
:includejavaruntime "yes"
:debug "true"
:target "1.5"}))

(target {:name "init"}
(tstamp)
(mkdir {:dir (i :build)}))

(target {:name "clean"
:description "Remove autogenerated files and directories"}
(delete {:dir (i :build)}))

)

Brian Doyle

unread,
Nov 6, 2008, 2:37:07 PM11/6/08
to clo...@googlegroups.com
On Thu, Nov 6, 2008 at 11:48 AM, Stuart Halloway <stuart....@gmail.com> wrote:

Hi all,

I am playing around with using Clojure to control Ant, something along
the lines of Groovy's Gant. I don't know how far I will take this--
right now it is serving as a code example for the book.

Two questions:

(1) Anybody interested in seeing lancet carried forward into a real
project?

Yes, I hate ant and pretty much anything would be better!  I might have
some time to help out with the implementation.
 


(2) Below is an example of lancet syntax (compare with Clojure's own
build.xml). Any big likes/dislikes?

No complaints from me.  I like the syntax.
 

carlitos

unread,
Nov 6, 2008, 4:19:41 PM11/6/08
to Clojure
On Nov 6, 7:48 pm, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> I am playing around with using Clojure to control Ant, something along  
> the lines of Groovy's Gant. [....]

I know next to nothing about ant, and what kind of control will lancet
provide, but the proposed syntax reminds me of what I got playing with
XML generation.
As an exercise, I tried to reproduce clojure's build.xml and pom.xml
(the output of the code below differs only in whitespace).
Your proposal is more succint (in particular when it comes to
properties), but I think it can be easily "expanded" to the
representation below (which maps directly into XML).

Cheers,

Carlos

(defn write-attributes [key val & attrs]
(print (format " %s=\"%s\"" (name key) val))
(when attrs (apply write-attributes attrs)))

(defn write-tag [data close]
(let [tag (name (if (coll? data)
(first data)
data))]
(print (format "<%s" tag))
(when (coll? data)
(apply write-attributes (rest data)))
(if close
(do (print "/>") nil)
(do (print ">") tag))))

(defn write-xml [tree]
(if (coll? tree)
(let [values (rest tree)
close-tag (write-tag (first tree) (not values))]
(when (or (not (= 1 (count values)))
(coll? (first values)))
(println))
(doall (map write-xml values))
(when close-tag
(println (format "</%s>" close-tag))))
(print tree)))

;; build.xml

(write-xml
'((:project :name "clojure" :default "jar")
(:description "Build with \"ant jar\" and then start the REPL
via \"java -cp clojure.jar clojure.lang.Repl src/boot.clj\".")
((:property :name "src" :location "src"))
((:property :name "jsrc" :location "${src}/jvm"))
((:property :name "cljsrc" :location "${src}/clj"))
((:property :name "build" :location "classes"))
((:property :name "clojure_jar" :location "clojure.jar"))
((:property :name "bootclj" :location "${cljsrc}/clojure/
boot.clj"))
((:target :name "init")
(:tstamp)
((:mkdir :dir "${build}")))
((:target :name "compile" :depends "init" :description "Compile
Java sources.")
((:javac :srcdir "${jsrc}" :destdir "${build}" :includeJavaRuntime
"yes" :debug "true" :target "1.5")))
((:target :name "jar" :depends "compile" :description "Create jar
file.")
((:jar :jarfile "${clojure_jar}" :basedir "${build}")
((:fileset :dir "${cljsrc}" :includes "**/*.clj"))
(:manifest
((:attribute :name "Main-Class" :value "clojure.lang.Repl"))
((:attribute :name "Class-Path" :value ".")))))
((:target :name "clean" :description "Remove autogenerated files
and directories.")
((:delete :dir "${build}")))))

;; pom.xml

(defn write-pom [pom]
(println "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
(write-xml
(conj pom '(:project
:xmlns "http://maven.apache.org/POM/4.0.0"
:xmlns:xsi "http//www.w3.org/2001/XMLSchema-instance"
:xsi:schemaLocation "http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd"))))

(write-pom
'((:modelVersion "4.0.0")
(:groupId "jvm.clojure")
(:artifactId "clojure-lang")
(:name "clojure-lang")
(:version "1.0-SNAPSHOT")
(:url "http://clojure.org/")
(:build
(:sourceDirectory "src/jvm")
(:scriptSourceDirectory "src/clj")
(:plugins (:plugin
(:artifactId "maven-compiler-plugin")
(:configuration (:source "1.5") (:target "1.5") (:optimize
"true"))))
(:resources (:resource (:directory "src/clj/"))))))

Stephen Wrobleski

unread,
Nov 6, 2008, 4:29:06 PM11/6/08
to clo...@googlegroups.com
On Thu, Nov 06, 2008 at 01:48:43PM -0500, Stuart Halloway wrote:
>
> Hi all,
>
> I am playing around with using Clojure to control Ant, something along
> the lines of Groovy's Gant. I don't know how far I will take this--
> right now it is serving as a code example for the book.
>
> Two questions:
>
> (1) Anybody interested in seeing lancet carried forward into a real
> project?

Oh yes please! I had started playing around with something like this, got
far enough to compile some Java source (a static base for some Clojure code
of course), and haven't really touched it sense.

> (2) Below is an example of lancet syntax (compare with Clojure's own
> build.xml). Any big likes/dislikes?

I've never liked XML DSLs because they lack standard general purpose
language features and go on to invent their own ad-hoc versions.

Is a property not just a 'def' ?

Is a target not a just function? (which only performs its actions if needed)

Isn't a project just a mapping from target names to functions, and dynamic
bindings during the build process?


; properties
(def src "src")
(def jsrc (str src "/jvm"))
(def cljsrc (str src "/clj"))
(def target "classes")
(def clojure.jar "clojure.jar")
(def bootclj (str cljsrc "/clojure/boot.clj"))

; deftarget is like defn but takes no args, and wraps the body in machinery
; that will only call it once per session.

(deftarget clean


"Remove autogenerated files and directories"

(delete :dir target))

(deftarget init
(tstamp)
(mkdir :dir target))

(deftarget compile-java
"Compile java sources"
(init)
(javac :srcdir jsrc :destdir target
:includejavaruntime true


:debug true
:target "1.5"))


A project could be defined explicitly, or could be created through
reflection (deftarget would also add some metadata in that case)

This syntax seems Clojurish rather than happens-to-be-on-Clojure. I think it
shows off both the cognitive simplicity of FP and the powerful incremental
nature of a Lisp based internal DSL.


Regards,
Steve

Stuart Halloway

unread,
Nov 6, 2008, 9:57:15 PM11/6/08
to clo...@googlegroups.com
Stephen,

You are absolutely right, and I hope to have all your syntax
suggestions implemented tomorrow.

By way of background: When I started, it seemed there were three
obvious avenues to pursue:

(1) write a Clojure DSL that generates the Ant XML
(2) write a Clojure DSL that sticks close to the underlying Ant object
model
(3) stick to Clojure idioms and use individual Ant classes when they
fit in

I rejected #1 out of hand--I don't think that the Ant XML has value,
and so wrapping it (and having it leak in the form of error messages)
was unappealing.

I picked #2 because I thought there were a ton of objects in the Ant
model I would end up wanting, and that they would be so intertwined
that I would need to use most of them in order to use any of them.

A few hours working on #2 was enough to convince me that there not
much in Ant that I wanted to keep. In particular targets, properties,
and subtask elements aren't worth their weight. That leaves only tasks
(and a stubbed-out project object).

So now I am proceeding through door #3. The work on #2 wasn't a total
waste -- I now know enough of the Ant object model to fake out the few
things I need (so far).

Cheers,
Stuart

Stuart Halloway

unread,
Nov 6, 2008, 10:01:16 PM11/6/08
to clo...@googlegroups.com
Carlos,

I went down a similar road once before, using a Ruby DSL to generate
the XML for Spring DI. This approach may offer the quickest initial
return, but it hits a ceiling very quickly. You end up having two APIs
with a totally unnecessary XML layer in between. Worse, the XML layer
spews error messages that are totally meaningless in terms of the new
object model.

I am going to skip the XML entirely and program against the parts of
the Ant object model I want to keep. It may be worthwhile to write a
tool that goes in the other direction, reading XML and emitting
lancet, for people porting existing buildfiles.

Cheers,
Stuart

fyuryu

unread,
Nov 7, 2008, 6:30:22 AM11/7/08
to Clojure
Driving ant from Clojure would be cool. I like the syntax of rake (but
I don't use ruby)
and started working on something similar. I also wanted to look at
ant's internals
to reuse some of its code (probably).

Here's what I'm working towards (taken from a presentation about
rake):

(task :build [:generate-html :copy-images])

(task :generate-html [:create-direcories]
(sh "someFile.exe --switch params "))

(task :copy-images [:create-direcories]
(cp "pics/rake.gif" "html/images/rake.gif")
(cp "pics/x.jpg" "html/images/x.jpg"))

(task :create-direcories
(mkdir "html")
(mkdir "html/images"))

Rake scripts look pretty simple and that is my goal, but I think it's
possible
to make ant simpler by getting the syntax right.

-- Roland

JGrant

unread,
Nov 6, 2008, 10:07:31 PM11/6/08
to Clojure
Stuart,

Not that I can remember the last time I used Ant but just want to say
'way to go'.
That syntax is so much more practical than Ant's choice of XML(Wasn't
XML based on S-Exps anyway, lol, we're coming full circle now). I'm
guessing that those folks that use Ant a lot will be glad to have
their build files shrinking to fractions of what they would if they
continue in classic Ant build XML.

Congrats also on the Clojure book !

-Justin

Stefan Bodewig

unread,
Nov 7, 2008, 4:03:13 AM11/7/08
to Clojure
[Reposting from gmail. Sorry if this becomes a dupe if/once my
original mail sent three hours ago gets unstuck]

Hi,

Given this is my first post here, a bit of background: I am an Ant
committer and have been for more than eight years. I'm a total newbie
when it comes to Clojure but have been doing Lisp (mostly Emacs Lisp
but dabbled a bit with CL) for longer than I'm using Java.

On Thu, 6 Nov 2008, Stuart Halloway <stuart....@gmail.com> wrote:

> (1) Anybody interested in seeing lancet carried forward into a real
> project?

Given this is something I wanted to look into myself in order to get
my feet wet, I'd like to see this going for forward. If only to
educate me.

If you need help finding your way through the historical cruft that
hides Ant's real model, I'll be happy to lend advice (I doubt I'd be
much help on the Clojure side right now).

Using a fake Project probably is the easiest approach, but there are
other extension mechanisms. Incidently I've written a blog article
last night showing a way to use a Java source file instead of XML as a
build file:

http://stefan.samaflost.de/blog/en/Apache/Ant/ant_javafront.html

Cheers

Stefan

Stefan Bodewig

unread,
Nov 7, 2008, 12:08:25 AM11/7/08
to clo...@googlegroups.com
Hi,

Given this is my first post here, a bit of disclosure: I am an Ant


committer and have been for more than eight years. I'm a total newbie
when it comes to Clojure but have been doing Lisp (mostly Emacs Lisp
but dabbled a bit with CL) for longer than I'm using Java.

On Thu, 6 Nov 2008, Stuart Halloway <stuart....@gmail.com> wrote:

> (1) Anybody interested in seeing lancet carried forward into a real
> project?

Given this is something I wanted to look into myself in order to get


my feet wet, I'd like to see this going for forward. If only to
educate me.

If you need help finding your way through the historical cruft that
hides Ant's real model, I'll be happy to lend advice (I doubt I'd be
much help on the Clojure side right now).

Using a fake project probably is the easiest approach, but there are

Reply all
Reply to author
Forward
0 new messages