I was trying to fix the build of a project last night. It used to unpack several dependent jar files before repackaging them along with the project code. How ugly. Then I remembered about one-jar, which lets you package things in a slightly more sensible manner, retaining the individual files.

The documentation isn’t as good as it could be. But after a bit of poking around, I came up with this ant task to build my jar.

  <property name="onejar" value="one-jar-boot-0.95.jar"/>

    <target name="dist" depends="compile">
        <!-- Set up the on-jar directory structure. -->
        <mkdir dir="${build.onejar.dir}" />
        <mkdir dir="${build.onejar.dir}/boot" />
        <mkdir dir="${build.onejar.dir}/lib" />
        <mkdir dir="${build.onejar.dir}/main" />
        <!-- First, build just our code into a jar of its own. -->
        <jar destfile="${build.onejar.dir}/main/main.jar"
                <attribute name="Main-Class"
                           value="net.happygiraffe.Main" />
        <!-- Next, copy in the libs we depend upon. -->
        <copy todir="${build.onejar.dir}/lib">
            <fileset dir="${vendor.lib.dir}">
                <include name="*.jar" />
                <exclude name="${onejar}" />
        <!-- Extract the One-Jar bits on top. -->
        <unjar src="${vendor.lib.dir}/${onejar}"
               dest="${build.onejar.dir}" />
        <!-- And finally, repackage. -->
        <jar destfile="${jar.path}"
             manifest="${build.onejar.dir}/META-INF/MANIFEST.MF" />

And then when I tried to run the jar, it fell over.

  Exception in thread "main" No such file or directory
          at Method)
          at java.util.jar.JarFile.<init>(
          at java.util.jar.JarFile.<init>(
          at com.simontuffs.onejar.Boot.main(

After substantial amounts of time messing around, it turned out that it’s a buug when you’re using Mac OS X and Java 5. The latest CVS code has a fix ( 1.14). Once I’d got the latest version from CVS, everything worked wonderfully. I only hope that it’s released soon.

Not only that, but when I looked through the CVS code, I noticed that there was an ant task as well. That would certainly simplify the rather verbose script above. I’ll have to look into that.

If you’re interested in the architecture of one-jar, check out the developerworks article Simplify your application delivery with One-JAR.


The Deployment Elephant

Tim O’Reilly covers much of what’s been crossing my mind recently in Operations: The New Secret Sauce. The really successful people are those who (like Google) have solved, and are continuing to solve the really hard problem of deployment. There is a huge gulf between programmers and sysadmins that needs to be crossed so you can get software that works really well. It’s all very well writing code that works “great on my PC”, but when you have to stick it on a Unix server blows up (reminds me of the “Best Viewed On My Monitor” graphics that festooned the web a few years back). We can and must do better.

Part of the problem is that nobody is seriously talking about deployment. During our company’s recent move towards Java, I’ve found it seriously hard to work out what best practises are and have already gone through several painful experiences working things out. Yes, this is part of the normal learning curve. But it would have been really, really nice to look them up in a “Deployment Patterns” book.

Update: on a tangentially related note, Steve Loughran notes:

There is a very simple test to see if the deployment process is working. If you have to go into the air-conditioned server room on a weekend or on your vacation, deployment is broken. If you are scared of the mobile phone ringing, because it may be the operations team, deployment is broken. If you are a week away from going live and you haven’t started bringing up the server, then the process is broken, you just don’t know it yet



I’ve spent some time this evening playing with SwitchTower. It’s a tool for deploying Rails applications. It’s just perfect for sending what’s on my test environment (Mac) up to my server (FreeBSD). Not only that, it’s relatively simple to get going, compared to many other deployment tools I’ve used (and written) in the past.

But it’s also very flexible. For example, just when I thought I’d gotten everything set up and running, I discovered that my database.yml file was wrong. It’s fine for development, but not the live server. Yet switchtower has a really handy feature where it can render a template into a file. So now I get my database.yml generated on install, pointing at the right place.

task :after_update_code do
  buffer = render("config/database.yml.rhtml", :shared_path => shared_path)
  put buffer, "#{release_path}/config/database.yml", :mode => 0644

Anyway, if you’re doing Rails at all, invest some time in learning SwitchTower. It doesn’t take long, and you’ll be much better off for it.