Tuesday, March 31, 2009

Executing command line scripts from Groovy on Windows

Today I had the need to create a number of dependencies within my local Maven repository (I know it's a hack you Maven purists, back off). I decided that I would use Groovy to loop over the jars in the lib directory and create the a dependency for each file. Groovyists know how easy this is:

new File('.').eachFile{
//do something

And of course I was aware that on Windows you have to use a "cmd /c" prior to your executable. So my final was going to look like this:

new File('.').eachFile{
groupId = it.name.substring(0, it.name.size() - 4)
"cmd /c mvn install:install-file -DgroupId=blahzy.blah-DartifactId=${groupId} -Dversion=9.9.9 -Dpackaging=jar -Dfile=${it.name}".execute().text

Seems appropriately short and succinct for my groovy instincts to feel okay with it. Only problem is that it didn't work. When I would run it the console would freeze and I had no idea what was going on. After reading through some of the groovy documentation online I found out that if the output is too much the Windows process will just freeze. Luckily there was a documented "hack" to solve the issue. My final script:

new File('.').eachFile{
groupId = it.name.substring(0, it.name.size() - 4)
thisCommand = "cmd /c mvn install:install-file -DgroupId=blahzy.blah-DartifactId=${groupId} -Dversion=9.9.9 -Dpackaging=jar -Dfile=${it.name}"
proc = thisCommand.execute()

So I don't get any of the output but it worked so who am I to complain.


paulk said...

There are versions of consumeProcessOutput that let you capture the output, e.g. in a StringBuffer (and they also use a separate thread to avoid the windows lock up problem). If you combined that with waitFor() you would probably get all the output with hopefully no hangs.

iamsteveholmes said...

That is very good to know. I believe I'll have to try it. If you have an example I would be happy to post it.

Anonymous said...

This works in Windows XP cmd 5.1.26:

outputCatcher = new StringBuffer()
errorCatcher = new StringBuffer()
proc = "cmd /c dir".execute()
proc.consumeProcessOutput(outputCatcher, errorCatcher)
println outputCatcher

This doesn't

["cmd", "/c", "dir"].execute().waitFor()

documented at codehaus

Monkey Search