Friday, June 5, 2009

Grails script runner featuring dependency on other projects

One of my favorite uses for Grails is scripting, as I've stated before. However, I stumbled over re-using code from other Grails projects in Eclipse.

With Java projects I'm used to interdependencies - for example larger projects are split up into sub-projects. All external libraries are put into the 'Lib' sub-project and can be used from the others, which makes the other projects look cleaner in Eclipse. To do this you simply use the Eclipse build path for the Eclipse compiler, and build.xml for Ant-driven build and deployment.

With Grails this isn't so straight-forward. In particular because running scripts does not go through build.xml at all. To influence the Eclipse compiler you can still use the build path, and include other Eclipse projects there. To influence what happens when you run a script from the command line you have to use a custom script runner. This isn't so bad because for some other features (enabling GORM) you have to use a custom script runner anyway.

An example is available here: ScriptRunner.groovy. Put it in your project scripts folder together with the scripts you want to run, and invoke it as grails [env] script-runner OtherScript [parameters..]

The magic for this particular purpose is in overrideCompilerPaths, which is mostly copied from _GrailsCompile.groovy in the Grails distribution but has the added line:

src(path: "${basedir}/../OtherProject/src/groovy") // added path

You'll have to add a line for each folder of each project you want to use code from. It isn't very elegant, so please let me know if you've found a better way to do this.

NB If you also use the Grails web app in this project, you'll also have to create a script like this: RunXApp.groovy, and instead of grails run-app use grails run-x-app.

It's a bit of a hassle, but once it's smoothed out you have a scripting environment where:
  • You can map domain classes to the database using only a few lines of code (using GORM and the data source provided by Grails you only have to add domain classes yourself).
  • You can use all the power of Grails, Groovy, Hibernate and Java from your scripts with zero extra setup.
  • You have a dynamically generated web app to view and edit your domain classes at virtually zero extra cost (you only have to run create-controller for each domain class and replace the controller body with def scaffold = default).
Neat.