Ant for Web Applications

Technical

On the whole, I suppose, Ant is probably best known as a build automation tool for "traditional" software projects (particularly Java), but its usefulness for building and deploying web applications should not be dismissed. I've been using Ant since maybe 2003 or 2004 to do just that. Admittedly, when I was first introduced to Ant, I was building a product - a distributed web application (a content management solution) - that included a fair amount of Java. That code had to be compiled and jar'd before it could be distributed with the rest of the code base. A colleague of mine at the time introduced me to Ant as a way of automating the Java component of the build, but it didn't take long to recognize the possibilities.

Once I became reasonably comfortable with what Ant was and what it could do, it became evident that it was a tool with a much broader use case than is usually assumed. These days I use it to deploy even the simplest web sites and applications. Here's the part where you, good reader, ask, "Why? It's easy enough to S/FTP/SCP the files from server to server." And then I answer, "In the simplest case, yes, but what if it's not simple? And either way, the automated process offers scalability because it can do more, takes less time to execute, can be executed unattended and does all of that in exactly the same way every single time." How is that not better? Sure, there's a little up front cost in the time it takes to create the script, but over time it's a huge time saver. Really.

To be honest, it's not even that time consuming up front. At least not any more. Over the years, I've come to realize that 90% of my web applications can be built and deployed in very much the same way. During that time, I've built and refined a template script that handles all of the core functionality. Sure, there are tweaks that need to be applied for most apps, but they're usually trivial; deploying most web applications is relatively prescriptive.

This entry offers a high-level view of how I use Ant to meet my own build and deployment needs. Subsequent posts will look at specific elements that are non-standard or that relate to how I integrate Ant into my end-to-end deployment process.

The Properties File (build.properties)

What makes the aforementioned tweaks trivial is the fact that I make heavy use of a properties file. This is a separate file containing nothing but variable assignments. In the properties file I define every piece of information that is specific to:

  1. The user that might be running the build (for example, authentication credentials)
  2. The build enviroment (that is, the machine on which the build is being executed)
  3. The targeted deployment environment (for example, staging or production).

Applying the stuff-and-things metaphor, the properties file handles the things that the Ant script needs to know in order to do the stuff it needs to do. The build file loads the properties file and then accesses the properties it defines just like any other variable set. Using this technique, the Ant script itself never needs to change unless the actual deployment process changes. The properties file, of course, will change significantly, but those changes are much easier to find and make in the properties file (which is much easier to read) than trying to alter the Ant file itself.

The heavy lifting, as you might expect, is all done by the build file.

The Build File (build.xml)

After writing build files for a while, I (all too) slowly came to realize that the process of deploying my projects almost invariably followed the same general path:

  1. Initialize the build. This might involve validating the properties set in the build.properties file, clearing any previous builds from the build machine and any other preprocessing-type work.
  2. Prepare the remote environment. There's usually some work to be done on the remote machine before I can actually deploy there. I tend to create a tarball of the current directory contents and archive it somewhere, for example (you know...just in case). Once it's archived, I also delete the current content so that I don't leave any garbage files on the server that may have been deleted from the code base.
  3. Get the code base. For me, that means exporting (not checking out) the code from Subversion. Exporting the code prevents the creation of those pesky .svn directories. This is also where I'll do any build-type exercises that are required to get the code on the build machine structured exactly the way it will be structured on the remote machine. For most projects, rearranging the directory structure isn't necessary, but sometimes there are very good reasons for the structure of the development code base to vary from that of production.
  4. Deploy the code. This is pretty much what it sounds like. Get the code from the build machine to the remote machine. It also includes any supporting tasks like modifying file ownership or permissions on the remote machine. It may also include executing a SQL script to create the database for a data-driven project.
  5. Garbage collection. Any clean up that should be done after a successful build/deployment. For example, deleting the build directory on the build machine so that it's ready to go the next time a build is run.
  6. Finalize (or formalize) the build. For me, this means tagging the code base in Subversion so that I have a snapshot of the code as it existed at the time of the build. You never know when you'll need to know what you deployed when.

An Ant script is comprised of targets and tasks. Targets are nothing more than named groups of (hopefully) related tasks. The high-level process defined above, for me, translates directly into my build targets: init, prepenv, getcode, deploy, clean and finalize. Each target includes at least one - and usually several - tasks.

Targets and Tasks

Initialize the Build (init)

The first thing I do in my init target is a little validation. In my properties file, I define a few properties for things like the project version and the Subversion revision number; I want to make sure that I (or any team member running the build) provides valid values for these. I use these values for branching and tagging in the finalize target, so I want them to make sense. For example, the revision number property defines the Subversion revision that will be exported and deployed. More often than not, that revision is the HEAD revision so it's tempting to not worry about finding out the number and to literally use the HEAD keyword. This value, though, is also used as part of my version numbering convention. Version 1.1.3 of the project would actually be, internally at least, version 1.1.3.3907 where 3907 is the Subversion revision number. It doesn't make much sense - or provide much information - if that version number reads "1.1.3.HEAD" so I validate to ensure that the property value is an integer.

After any validation, I use the project name property value to derive a file system friendly name. This will be used to create a top level build directory and as a name for the tarball I create of the existing files on the remote machine. For my builds, the project name value itself is mixed case and human readable because it's used in some publicly accessibly text (commit messages for tags and branches, for example). To make it file system friendly, I force the text to lowercase and replace non-alphanumerics with a hyphen. Ta da! File system friendly. "My Project Name" becomes "my-project-name".

Assuming these tasks complete successfully, I delete the build directory (if it exists, it's named using the file system friendly name just created) so that everything's ready to go.

Prepare the Remote Environment (prepenv)

As I mentioned, the first thing I do before messing with the remote environment is create a tarball of the existing content. Usually unnecessary, but you never know. There have been times when I've been very happy that I included this task. Once the existing content has been archived, I can delete it. For most sites and applications, that's pretty much all I do for this target.

Export the Code Base (getcode)

Technically speaking, the name of this target is only half right. Really what I'm doing here is getting code and, if necessary, manipulating it. Using an external task library named SvnAnt, I can export code from my Subversion repository to my build directory. If my repository is organized a bit differently than my deployed code should be then I'll get everything organized before deploying. I prefer to do as little work on the remote server as I can get away with so I do it on the build machine instead.

In a previous post, I described a method for using Ant to write config files. Although I haven't applied this to my template yet, this is the target where I'll add that functionality.

Deploy the Application (deploy)

Not a lot of mystery here. The tasks in this target move the code base from the build machine to the remote machine. It can be a bit more than that, though. This is where all constructive activity on the remote machine occurs (as distinguished from destructive activity - like delete - which occurs in the clean target). For example, a lot of my applications require file uploads. In my configuration, that means that the apache user needs to have write permissions to the upload directory. When moving files, that doesn't just magically happen. After the files are moved, I ask my Ant script to SSH into the remote machine, execute chmod and, if necessary, chown to set the permissions as needed. It's also my practice to script the database completely - create the database, add users, set permissions, create tables...everything. This is handled by Ant as well - again, by SSHing into the remote machine and executing the MySQL source script.

Other tasks may be required for some applications and other applications may not even require all of these, but Ant has it covered either way. Chances are, if something needs to be done on the remote machine, Ant can take care of it.

Garbage Collection (clean)

I hate system clutter and, almost inevitably, the build/deployment process introduces some kind of clutter that my OCD demands that I scrub.

Finalize the Build (finalize)

By the time the build execution reaches this target, the build itself is complete...and successful. My build process, though, includes branching and/or tagging my code base. I do that in this target - again using SvnAnt. Think of this target as a vehicle for post-processing instructions, if you will.

Epilogue

So that's a pretty comprehensive, birdseye view of how I use Ant to build and deploy web applications. In the next few days (or weeks, depending on how much time I get to write, I'll fill in some of the details that will lead to a rich template script.

tags:
Subversion, Ant, build
Lokesh said:
 
Thanks for the great write-up on ANT. Perusing through the archives now. Keep it up!
 
posted 186 days ago
Add Comment Reply to: this comment OR this thread
 
Richard Davies said:
 
Great post, Rob! Would you mind posting your build.properties and build.xml file? It sounds like they'd make a great template for helping me get started with my new build process.
 
posted 83 days ago
View Replies (4) || Add Comment Reply to: this comment OR this thread
 
.: HIDE REPLIES :.
Rob said:
 
@Richard -

Sure. I may not be able to do it for a week or so due to travel, but I'll be happy to post. Look for it on my current site, though: http://robwilkerson.org.

Thanks.
 
posted 83 days ago
Add Comment Reply to: this comment OR this thread
 
Rob said:
 
@Richard -

Haven't forgotten about you. I'm actually in the latter stages of a significant rework of my build templates. As soon as they're ready, I'll post them on my new site and add a comment here.
 
posted 59 days ago
Add Comment Reply to: this comment OR this thread
 
Richard Davies said:
 
Thanks for the update... I was beginning to think that you had forgotten about me! ;-)
 
posted 59 days ago
Add Comment Reply to: this comment OR this thread
 
Rob said:
 
Nah, it's something I've been wanting to do for a while - build a little more intelligence in the script and add a few sanity check pauses - but only recently got around to starting. I should be done later this week which would mean a follow-on post this weekend or early next.

I'm also in the midst of a work laptop changeover to Linux, so that's eating up some of my after hours time. :-)
 
posted 57 days ago
Add Comment Reply to: this comment OR this thread
 
Rob said:
 
For Richard and anyone else that's interested, I should be finished updating my build script templates this morning (finally). Look for them to make an appearance at http://robwilkerson.org sometime this weekend or early next week.

Thanks for your patience.
 
posted 35 days ago
Add Comment Reply to: this comment OR this thread
 
Rob said:
 
Okay, I've committed. Before actually releasing the scripts, I want to put out some background info to ensure that everyone understands the assumptions the script makes and how/why it operates the way it does, but the introductory post has been published on http://robwilkerson.org.

Hopefully inertia works and the body in motion will stay in motion.
 
posted 31 days ago
Add Comment Reply to: this comment OR this thread
 

Search

Rob  Wilkerson