Quite often it is needed to execute Groovy script within a Grails application context (including access to domain objects, controllers, services, etc). Unfortunately there is no such built-in functionality in Grails.

However Ted Naleid has written run-script Gant script to do this and published on his blog.

We used it in our project and it worked flawlessly. However it stopped working with upgrade to Grails 1.3.1 and even grabbing the latest version from bitbucket haven’t helped.

So I looked into the sources of built-in Grails scripts, including run-test and hacked run-script a little bit to make it run fine.

You can grab/fork the resulting script on github.

Also, please vote for inclusion of run-script functionality into main Grails distribution in JIRA

Using the script is easy. Just store it in src/scripts/ folder of your Grails app with RunScript.groovy filename.

Then you’ll be able to run your scripts as following:

grails run-script path/to/script1/Script1.groovy path/to/script2/Script2.groovy ...

The script itself is:

import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
import org.springframework.orm.hibernate3.SessionFactoryUtils
import org.springframework.orm.hibernate3.SessionHolder
import org.springframework.transaction.support.TransactionSynchronizationManager

includeTargets << grailsScript("_GrailsBootstrap")
includeTargets << grailsScript("_GrailsRun")
includeTargets << grailsScript("_GrailsSettings")
includeTargets << grailsScript("_GrailsClean")

target('default': "Execute the specified script after starting up the application environment") {
    depends(checkVersion, configureProxy, packageApp, classpath)
    runScript()
}

target(runScript: "Main implementation that executes the specified script after starting up the application environment") {
    parseArguments()
    if (argsMap["params"].size() == 0) {
        event("StatusError", ["Required script name parameter is missing"])
        System.exit 1
    }
    compile()
    loadApp()
    configureApp()
    configureHibernateSession()
    argsMap["params"].each { scriptFile ->
        executeScript(scriptFile, classLoader)
    }
}

def configureHibernateSession() {
    // without this you'll get a lazy initialization exception when using a many-to-many relationship
    def sessionFactory = appCtx.getBean("sessionFactory")
    def session = SessionFactoryUtils.getSession(sessionFactory, true)
    TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session))
}

def executeScript(scriptFile, classLoader) {
    File script = new File(scriptFile)
    if (script.exists()) {
        def shell = new GroovyShell(classLoader, new Binding(ctx: appCtx, grailsApplication: grailsApp))
        shell.evaluate(script.text)
    } else {
        event("StatusError", ["Designated script doesn't exist: $scriptFile"])
    }
}
 

Shameless plug

We develop mobile and web apps, you can hire us to work on your next project.