Friday, March 8, 2013

symlinks for live coding

tl;dr: Use Unix symlinks to point from under an exploded .war file into the static part of your source code tree and then add allowLinking="true" to your Tomcat context.xml file to enable a much faster code/run loop without having to reconcile changes later.

At my old job, I got spoiled by not needing any kind of build process to see changes I was making live, as long as I was just editing the static files. (Well, mostly static; we used some good ol' (emphasis on "ol'") serverside includes (SSI))

My new place, a lot of the work is meant to take place in a separate source code tree, then there's an ant process that builds a war. The build can be pretty fast, but still the difference between "edit, save, switch to browser, reload" and "edit, save, switch to terminal, build, switch to browser, reload" is surprisingly large. (Even a "continuous deployment" system monitoring changes can be kind of slow, waiting for the change to be noticed, the build, the copy, and the redeploy.)

The .war file was already exploded, so I started editing live in the folders inside the exploded war. Back in business! The trouble was when it was time to check-in; i had to isolate the changes I made, get them back to the source tree, and only then could I check-in. (Also, it always felt like there was a risk of firing off a build and overwriting the changes with the source tree version.)

I started by looking at directory compare tools. "Beyond Compare" for Windows is great, but it's not for OSX. I then found out diff has some arguments that will let it handle directories:
diff -rq srcdir livedir
The "r" means recursive (i.e. go down the directory structure) and the "q" stands for "quiet", i.e. just say which files are different, not how they differ.

That wasn't bad, but the output wasn't super friendly (with no clear way of saying "ignore svn files and what not) and there was no simple way to merge in the changes then.

I was thinking about making my own "deepdiff" tool, maybe in node.js, and started down that path when I had another thought: I'm on OSX. OSX is a Unix-variant. Unix has symlinks! A symlink is a way of giving a new additional path (like under a war) to content that actually exists elsewhere on the filesystem (like in the source tree).

The syntax for that is
ln -s existing_path new_name_for_it

So I made a symlink inside the exploded war into where the static files live in the source tree, and it didn't work. Tomcat needs to be told to allow these links (otherwise it can be a little bit of a security risk. The secret sauce was setting allowLinking to true in the Context tag in config.xml

<Context allowLinking="true">

Config.xml can live in a few different places, and there are some rules about handing overrides and what not, so I found it simplest to hack that into appserver/conf/context.xml -- there might be slightly better places to put but that's beyond the scope of this humble blogentry.

No comments:

Post a Comment