Friday, March 16, 2007

Groovy on OS X and MacPorts

Update Note: This is still the case with Groovy 1.6.x and Leopard the same fix still works.

The default MacPorts install of groovy didn't work out of the box. When I ran groovy from the prompt I got a nasty java.lang.SecurityException.

The problem ended up being that my Java CLASSPATH included classes.jar.

The solution ended up clearing out the CLASSPATH system variable altogether before invoking groovy. You can do this with a command line switch but the easiest way to do it was to edit the startGroovy file (found in the /bin directory of the groovy installation). A fast way to find this is using Spotlight

I simply added CLASSPATH= as the first thing in the file:

...
##
## $Revision: 4298 $
## $Date: 2006-12-04 02:39:45 +0100 (Mo, 04 Dez 2006) $
##

CLASSPATH=

PROGNAME=`basename "$0"`
...

Groovy Process Piping: Follow-up

Thanks to some comments from those a bit more savvy on this topic I'm suggesting the following method from charlesanderson:

p=['sh','-c','ls -l | sort'].execute()
println p.text

This is mostly cross-platform (assuming CygWin) and is nicely succinct.

I like this method over using the Groovy Groosh module as suggested by Yuri Schimke if only because it doesn't require an import:

def f = gsh.find('.', '-name', '*.java', '-ls');
f.pipeTo(lines);

As always there are many ways to skin the same cat.

Monday, March 12, 2007

Groovy Process Piping

I was playing around with using Groovy as a shell scripting language. While convenient, I found that shelling out to my trusted unix commands is many times faster for file operations than handling them within Groovy.

Creating and executing a process is trivial in groovy:

p = "ls -l".execute()
println p.text
But using pipes or redirection is not allowed:

p = "ls -l | sort".execute()
println p.text
For some reason it took me awhile to understand the java.lang.Process well enough to come up with this script, which contains a helper class for piping one Unix shell command into another.
def class Pipe {
private Process p

def Pipe(cmd) {
p = cmd.execute()
p.out.close()
}

def to(cmd) {
def p2 = cmd.execute()
p2.out << p.in
p2.out.close()
p = p2
this
}

def text() {
p.text
}
}

def output = new File('output.txt')
output.delete()

output << new Pipe("grep -h -e '^.* ERROR .*' input.txt")
.to("sort")
.to("tail -n50").text()


Note 1: The Process object is in the standard JDK so with a bit of alteration, one could create the Pipe utility in straight-up Java. But in regular Java I wonder how often one needs to run a shell command?

Note 2: If you are on Windows and are using Cygwin you'll need to be aware that the Windows "sort" command clobbers the Unix version and is hardly as robust. You may need to hard code which sort you want to use: "C:\\cygwin\\bin\\sort"