Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

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 "targets" that can depend
on each other and invoke other targets (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:

Code Block
titleMyScript.groovy
target('default':"The target description") {
	depends(clean, compile)
	jar()
}
target(clean:"Delete stuff") { ant.delete(dir:"build") }
target(compile:"Compile stuff") {
	mkdir(dir:"build/classes")
	javac(srcdir:"src", destdir:"build/classes")
}
target(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:

Code Block
target ('default': "Performs compilation of Java sources") {
	compile()
}

target(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 ensures that you can 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:

Code Block
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:

Code Block
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" target defined
within the script.

Any parameters you add to the command will be available in the args variable in your default target.

Code Block
grails my-script anyparameters

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 Block
grailsHome = ant.project.properties."environment.GRAILS_HOME"
includeTargets << new File ( "${grailsHome}/scripts/Package.groovy" )

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

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 target 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:

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

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

	// reference a Grails class here
}

If you don't depend on this target, 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 Block
import org.springframework.orm.hibernate3.*

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

target('default':"My Funky Script") {
	depends( configureProxy, packageApp, classpath )

        // configure context class loader to have access to domain classes
	classLoader = new URLClassLoader([classesDir.toURI().toURL()] as URL[], rootLoader)
        Thread.currentThread().setContextClassLoader(classLoader)

        // configure and load application
        bootstrap()

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

	def sf = appCtx.getBean("sessionFactory")

	def template = new HibernateTemplate(sf)

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

What the Bootstrap.groovy script does is place a "grailsApp" variable which is an instance
of GrailsApplication and a "appCtx" which is the Spring ApplicationContext