Monday, June 06, 2005

Reason # 431 Why You Should Use Cygwin/Bash Instead of the Windows Command Prompt

I'm working on a project right now that has a huge number of classes, and a corresponding huge number of tests. The whole thing builds via Ant (big surprise there). Currently, I'm writing code in a fairly isolated part of the project, and I've been working a few days on getting a new class Just Right. Getting it Just Right, of course, means unit tests and test first coding. The upshot is that I find myself needing to run the build target and then the target that runs the test suite over and over. I like to run both ant targets at the same time, but I need to know if the build doesn't work (e.g., if I get a compiler error, I don't want to run the tests). Rather than monkey with the ant build file to add this transient behavior, bash comes to the rescue. More and more, I do all my command line stuff in bash for reasons like this. Here is the command I invoke 30 or 40 times a day (all on 1 line, it may wrap here):

if ant; then ant runatest -Dtesttorun=com.thoughtworks.logging.AllTests; fi

This runs the default ant task (which builds everything). If the return code is 0, it then runs the "runatest" target. The test runs only if the build was successful. This little trick takes advantage of the fact that ant is smart enough to tell the underlying OS (regardless of the shell) if it passed or failed. The "fi" at the end is the "end if" indicator for bash.

Yes, you can create the same kind of little batchy kind of thing in Windows, but I never think to. It seems somehow more natural to me to think in terms of automation, shell scripts, and command chaining in bash than it does Windows. Maybe it's because bash is far, far more powerful than the command line tools in Windows. I never run anything in a Windows command shell now that I unless I'm forced.


Jonas Bengtsson said...

Not to bash bash or anything, but are you aware of the && feature in the Windows Command Prompt?

You can execute a series of commands by adding && inbetween. And it is supposed to honor the errorlevel, so if any commands fail, the rest shouldn't execute. Unfortunately most commands I run on a daily basis doesn't leave any errorlevel, so I'm not sure if that part works.

ade said...

The same feature works in bash. So I typically use:

foo && bar

Bar only gets run if foo succeeded.

And of course this feature is built into Ant anyway. Typing:

ant foo bar

will only run bar (and related targets) if foo succeeds. This does depend on your build file having been set up so that a failure of foo fails the build.

And finally if you're using cygwin you really ought to take a look at:

Chris said...

Or just dual boot your machine between Windows (for games) and Linux (for everything else)? :)

Neal Ford said...

Here's the quote:

"UNIX" for Longevity
"AS/400" for Nostalgia
"Linux" for Productivity
"MAC" for Multimedia
"Windows" for Solitaire

Dan Mercier said...

Uhm not sure why you're averse to changing the buildfile. Having your build task halt on failure seems to be a standard procedure? Why would you run tests on code that doesn't compile.

Once you have the building halting on failure you just ant build run.test
or in your cast ant -Dtesttorun=com.thoughtworks.logging.AllTests build runatest

Neal Ford said...

You are right -- changing the buildfile is the better long term solution. However, because of the way the build file works, the "runatest" target doesn't depend on "all" to build everything. The "test" target does -- build everything, then run a test. However, if you just want to run a single test, you don't have to take the time hit to build everything every time. I could create a target that depends on "build,runatest", but the reason I'm doing this goes away in another couple of days. The way I'm doing it is just easier.

Linux Unix said...

Very informative blog. Please check out my linux wallpaper blog.

Gordon said...

Hello, your blog is informative. I have a linux server related website, please visit and hope that it is helpful to you