Replacing Ant with Rake has been a compelling idea for some years now. Until now I wasn’t convinced that you weren’t going to have the same issues as Ant – poorly factored builds that rapidly evolve into a project specific DSL. This may change things.
The build system, or grammar as Simon calls it allows you to break a typical monolithic build file down into a collection of fragments. Each fragment can have one or more targets declared, and each target has some attributes. More at CrazyFunBuild.
Simon is undergoing an exceptionally drawn-out email interview on the process:
Your build tool is one of a few new players. What was your motivation for adding to the build gene pool? Were you scratching an itch, or do you have a broader motive?
Definitely scratching an itch. WebDriver started off as a simple java
project, but it quickly became obvious that it’d also be useful to
have language bindings for things like C#, ruby and python. I could
have settled on a separate build tool for each language, but there are
places where a Java component depends on a DLL (for example) Switching
build tools repeatedly when constructing a single logical unit seemed
wasteful, so I started looking around for a build tool that would
provide support for all the languages I wanted to use.
I failed, but settled on rake because it had poor support for everything 🙂
The next problem was that as the project grew, so did the Rakefile. It
ended up being obscenely long and increasingly fragile, and in the end
I was about the only person who would confidently hack around in
there. An obviously sub-optimal state of affairs. The first step in
fixing this was to break out common tasks into functions (because a
Rakefile is just a ruby script in disguise) This still left a pretty
large build file to deal with, so the next stage was to allow us to
break the script into pieces. The obvious issue is that if you do
this, where are paths relative to? The location of the top-level
Rakefile? Or the fragment of code in the subdirectory? Worse, it’d be
unwise to have duplicate task names (“test”) but detecting those while
writing a fragment of a build file would be troublesome at best.
At the same time, I like my builds to be as declarative as possible,
only breaking through the “fourth wall” to scripting when necessary.
Encouraging people to leave lots of little scripts that are the pieces
of a larger application as build files seemed like the worst way of
achieving that goal of “declarativeness”. So, I wrote a parser for a
sub-set of ruby (which mutated into a subset of python) using ragel
that parses build files and generates rake targets based on the path
to the build file and the name of the target in that file. It’s by no
means an original idea: the only thing I can take even a crumb of
credit for is the current implementation (and it’s pretty much
designed to work with selenium, so there are lots of corners cut in
By clearly defining the build grammar, there’s also a chance to
clearly define how paths are interpreted, so that neatly side-steps
that problem. I also provided an “escape hatch” so that you can call
out to other rake tasks as required. Better this is just a thin skin
around other build tools (the java parts delegate to ant controlled
programatically, and the .net pieces use visual studio) but it means
that anyone can read the build files and understand how the source
code, regardless of language, is transformed into a binary.
So, yeah, scratching the itch of “I want a single, declarative build
tool that allows someone not familiar with the other build tools used
to understand how the system works, and which can work with multiple
languages”. Right now, it’s specific to the project, and I’m
comfortable with that: I want to write a browser automation framework,
not a build grammar or (worse) a build tool. 🙂
To be continued