Grails - Command Line Scripting

Command Line Scripting (Since 0.4)

Basics

Grails supports command line scripting using a Groovy ant wrapper called Gant

A Gant script is essentially a Groovy script that defines special "tasks" that can depend on each other and invoke other tasks (just like Ant). The bonus is that your build files are written in Groovy not XML.

A basic Gant script in Grails looks like this:

task('default':"The task description") {
	depends(clean, compile)
	jar()
}     
task(clean:"Delete stuff") { Ant.delete(dir:"build") }
task(compile:"Compile stuff") { 
	Ant.mkdir(dir:"build/classes")
	Ant.javac(srcdir:"src", destdir:"build/classes")
}                               
task(jar:"Package stuff") {
	Ant.jar(basedir:"build/classes", destfile:"build/myproject.jar")
}

The above of course is a very simple build, as your build gets more complex the power of Groovy comes in handy. Note the use of the implicit "Ant" instance

Using Ant from a Gant script

You can use Ant from a Gant script using the implicit Ant variable. For instance consider this example from the Compile.groovy Gant script in $GRAILS_HOME/script:

task ('default': "Performs compilation of Java sources") {
	compile()
}

task(compile : "Implementation of compilation phase") { println "Compiling sources.." Ant.sequential { mkdir(dir:"${basedir}/web-app/WEB-INF/classes") path(id:"classpath") { fileset(dir:"lib") fileset(dir:"${grailsHome}/lib") fileset(dir:"${grailsHome}/dist") fileset(dir:"${basedir}/web-app/WEB-INF/classes") } javac(srcdir:"${basedir}/src/java", destdir:"${basedir}/web-app/WEB-INF/classes", classpathref:"classpath",debug:"on", deprecation:"on", optimize:"off")

} }

Here the script uses the Ant variable in combination with the {{sequential}} method which allows you to omit the Ant prefix before each Ant call such as {{mkdir}}, {{javac}} and so on

Creating & Executing a Script in Grails

You can create a Gant script in Grails by executing the command:

grails create-script MyScript

The above will create a Gant script in $PROJECT_HOME/scripts, but this is not the only place they can live as we will see in the next section.

To execute the above script you can type the command:

grails my-script

What happens here is that Grails uses a convention to convert the command number (in lower case, separated by underscores) into the script name (in camel case) and then invokes the "default" task defined within the script.

Where do Gant scripts live?

In Grails Gant scripts can live in a number of places defined below:

  • $GRAILS_HOME/scripts
  • $PROJECT_HOME/scripts
  • $USER_HOME/.grails/scripts
  • $PROJECT_HOME/plugins/*/scripts
If there are multiple scripts of the same name in these locations Grails will prompt you for a choice of which one you want to execute. In other words, one script never overrides another.

Useful Grails provided Scripts

Grails provides a number of scripts that are built in that can be re-used. Within the $GRAILS_HOME/scripts directory you will find these. For example the {{Compile.groovy}} script allows you to depend on Grails' compilation step or the {{Package.groovy}} script allows you to depend on Grails' packaging step (which involves the generation of web.xml on the fly)

To rely on these in your code you need to "include" them in your Gant script. The general way to do this is via establishing the GRAILS_HOME environment variable:

code: null
grailsHome = Ant.project.properties."environment.GRAILS_HOME" includeTargets << new File ( "${grailsHome}/scripts/Package.groovy" )

task('default':"My Funky Script") { depends( package ) }

code: null

in the example above we include the {{Package.groovy}} script and depend on its {{package}} task to ensure Grails is packaged correctly before executing our task.

Setting up the Grails classpath

Another useful task to depend on is within {{Init.groovy}} called {{classpath}} that does the job of setting up the classpath using Groovy's RootLoader so that referencing within the lib, classes or grails-app dir doesn't throw a ClassNotFoundException:

grailsHome = Ant.project.properties."environment.GRAILS_HOME"    
includeTargets << new File ( "${grailsHome}/scripts/Init.groovy" )

task('default':"My Funky Script") { depends( classpath )

// reference a Grails class here }

If you don't depend on this task then an exception is thrown. Note that this is done because some tasks need to delete classes (like Clean.groovy) and certain systems (like Windows) disallow this if they have been loaded by the JVM

Bootstrapping Grails inside a Gant script

Sometimes it is useful to bootstrap the whole Grails environment inside a Grails script. This is what some of the scaffolding and unit testing task do for example. To do this you can depend on the {{Bootstrap.groovy}} script:

code: null
import org.springframework.orm.hibernate3.*

grailsHome = Ant.project.properties."environment.GRAILS_HOME" includeTargets << new File ( "${grailsHome}/scripts/Bootstrap.groovy" )

task('default':"My Funky Script") { depends( bootstrap )

def bookClass = application.getDomainClass("Book").getClazz()

def sf = ctx.getBean("sessionFactory")

def template = new HibernateTemplate(sf)

def books = template.loadAll(bookClass) books.each { println it.title } }

code: null

What the {{Bootstrap.groovy}} script does is place a "application" variable which is an instance of GrailsApplication (+) and a "ctx" which is the Spring ApplicationContext (+)