Using Gant to execute a groovy script within the Grails context (updated)

2008/03/31

In a previous post I showed a script that I had created to allow the execution of a groovy script within a grails application context (including access to domain objects, controllers, services, etc). A couple of people reported a problem with the script where they were getting lazy initialization exceptions. I finally tracked this issue down to one where many-to-many relationships are being used between two domain classes.

Here is an updated script that fixes this issue by setting up the hibernate session in the Gant script.

scripts/RunScript.groovy:

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
 
grailsHome = Ant.project.properties."environment.GRAILS_HOME"
 
includeTargets << new File ( "${grailsHome}/scripts/Package.groovy" )
includeTargets << new File ( "${grailsHome}/scripts/Bootstrap.groovy" )
 
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()
    classLoader = new URLClassLoader([classesDir.toURL()] as URL[], rootLoader)
    Thread.currentThread().setContextClassLoader(classLoader)
    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"])
    }
}
 
// this argument parsing target has actually been submitted as a patch to Init.groovy after some feedback
// on the grails user mailing list and will hopefully be in the next release of grails.
// Vote it up if you like it: http://jira.codehaus.org/browse/GRAILS-2663
 
argsMap = [params: []]
 
target(parseArguments: "Parse the arguments passed on the command line") {
    args?.tokenize().each {  token ->
        def nameValueSwitch = token =~ "--?(.*)=(.*)"
        if (nameValueSwitch.matches()) { // this token is a name/value pair (ex: --foo=bar or -z=qux)
            argsMap[nameValueSwitch[0][1]] = nameValueSwitch[0][2]
        } else {
            def nameOnlySwitch = token =~ "--?(.*)"
            if (nameOnlySwitch.matches()) {  // this token is just a switch (ex: -force or --help)
                argsMap[nameOnlySwitch[0][1]] = true
            } else { // single item tokens, append in order to an array of params
                argsMap["params"] << token
            }
        }
    }
    event("StatusUpdate", ["Done parsing arguments: $argsMap"])
}

If you save that in your application’s scripts directory as RunScript.groovy you can execute it like this:

grails run-script [path-to-script-1] [path-to-script-2]...[path-to-script-n]

The paths are relative to the root of the grails application directory. To see it’s potential use, if you had a directory in your app called userScripts that contained a script createBook.groovy that exercises the many-to-many relationship:

def theTalisman = new Book(title: "The Talisman").save()
def stephenKing = new Author(name:"Stephen King").addToBooks(theTalisman).save()
def peterStraub = new Author(name:"Peter Straub").addToBooks(theTalisman).save()def book = Book.findByTitle("The Talisman")
println "Found ${book.title} with authors = ${book.authors*.name}"

If you had these domain classes:
Author.groovy

class Author {
static hasMany = [books:Book]
String name
}

Book.groovy

class Book {
static belongsTo = Author
static hasMany = [authors:Author]
String title
}

You could then run the script:

grails run-script userScripts/createBook.groovy

And you’d see the output:

Found The Talisman with authors = ["Stephen King", "Peter Straub"]

Since you’re running in the grails context, you also have access to all of your service and controller classes. Anything that you can do inside grails can also be scripted using this target.

Without the new fix that configures the hibernate transaction on the session (configureHibernateSession()), you’d see this error instead:

failed to lazily initialize a collection of role: Book.authors, no session or session was closed

Thanks to Peter Wolf on the GUM mailing list for reporting an issue and testing things out as well as Armin Heinzer for the pointer to the suggested fix on the grails-user list.

There are 46 comments in this article:

  1. 2008/04/11Josh Reed say:

    Hey Ted,

    Thanks for this work. I ran into a few problems when I was trying to cut and paste this into my Grails install.

    1) On line 4, it looks like Wordpress ate a line break. It should end after: TransactionSynchronizationManager

    2) Some of the double quotes got converted to nice HTML double quotes. When you cut and paste, make sure you just do a global search and replace to standard double quotes ”

    3) Finally, the regex in the parseArguments target doesn’t work for me. If I type:
    grails run-script userScripts/populateDatabase.groovy
    This matches the nameOnlySwitch. Just looking at the regex, this makes sense to me because you have “-?(.*)” which I interpret as “zero or one dashes followed by anything”. If I switch it to “-(.*)” or “-+(.*)” (one or more dashes) this falls through and the script name gets picked up. Maybe this is another cut and paste artifact.

    Thanks for the good work.

    Cheers,
    Josh

  2. 2008/04/11Josh Reed say:

    Just a quick follow up, the reason why things were failing was because the double dash got converted to an mdash. So it really should be two separate dashes and then the question mark, which makes more sense from a regex standpoint.

    Cheers,
    Jsoh

  3. 2008/04/15tednaleid say:

    Ack…Thanks Josh. I’ve been having some trouble getting wordpress to not screw up my code.

    I believe that I’ve fixed it above, but here’s a pastie link if that causes problem s for anyone.

  4. 2008/04/16Armin Heinzer say:

    I tried this new version. I could read and create new objects, but I was not able to update an existing object which was read from database before. Such updates were ignored:

    b = Book.get(1)
    b.name += ‘ updated’
    b.save()

    I added following lines to the script and now updates works as well:


    import org.codehaus.groovy.grails.support.*

    configureHibernateSession()

    // added new
    appCtx.getBeansOfType(PersistenceContextInterceptor).each { k,v ->
    v.init()
    }

    argsMap["params"].each { scriptFile ->
    executeScript(scriptFile, classLoader)
    }

    // added new
    appCtx.getBeansOfType(PersistenceContextInterceptor).each { k,v ->
    v.flush();
    v.destroy()
    }

    May be this is not the most elegant solution (I am not a grails expert yet), but at least it fixed my problem.

    Armin

  5. 2008/05/27along say:

    there is something wrong:
    includeTargets >> new File ( “${grailsHome}/scripts/Package.groovy” )
    includeTargets >> new File ( “${grailsHome}/scripts/Bootstrap.groovy” )

    here “>>” should be “<<”

  6. 2008/05/27tednaleid say:

    @along

    Thanks for the note! It got messed up when I initially posted it and wordpress ate the less than signs, I manually edited it and put the wrong ones in, oops. Should be fixed above now.

  7. 2008/05/30Oliver say:

    Hi

    Excellent work. Thanks for sharing it with us. One question though: In which grails environment is the script running? Development? If so, how is it possible to specify a different environment?

  8. 2008/05/30tednaleid say:

    @Oliver

    By default, scripts run in the development environment. You can run any script in another environment by using the -Dgrails.env <env_name>parameter.

    Here’s an example running in the “test” environment (where environments are defined in the grails-app/conf/Config.groovy file)

    grails -Dgrails.env=test run-script userScripts/createBook.groovy

    You can take a look at the environments section of the Grails documentation for more information.

  9. 2008/05/31Oliver say:

    Thanks. Another question: It is currently not supported to pass arguments to the script because you basically treat all arguments as seperate script files right?

  10. 2008/05/31tednaleid say:

    @Oliver, yes, the current script doesn’t pass any arguments to the script and simply treats all parameters as separate script files.

    It wouldn’t be that hard to change it to have it instead only parse a single file and pass the parameters along to the calling script.

    The call to parseArguments would simply grab the first parameter as the file name and create a variable that contains the remaining arguments.

    Then, executeScript would add the remaning parameters as a new item in the Binding object.

    Here’s an updated script with these changes (I called it RunScriptWithParms.groovy):

    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
     
    grailsHome = Ant.project.properties."environment.GRAILS_HOME"
     
    includeTargets << new File ( "${grailsHome}/scripts/Package.groovy" )
    includeTargets << new File ( "${grailsHome}/scripts/Bootstrap.groovy" )
     
    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()
        classLoader = new URLClassLoader([classesDir.toURL()] as URL[], rootLoader)
        Thread.currentThread().setContextClassLoader(classLoader)
        loadApp()
        configureApp()
    	configureHibernateSession()
    	scriptFile = argsMap["params"].getAt(0)
    	// remove our script name from the params so when we call the script it's not in there
    	argsMap["params"].remove(scriptFile)
        executeScript(scriptFile, classLoader, argsMap)
    }
     
    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, argsMap) {
        File script = new File(scriptFile)
        if (script.exists()) {
            def shell = new GroovyShell(classLoader, new Binding(ctx: appCtx, grailsApplication: grailsApp, argsMap: argsMap, args: args))
            shell.evaluate(script.text)
        } else {
            event("StatusError", ["Designated script doesn't exist: $scriptFile"])
        }
    }
     
    // this argument parsing target was submitted as a patch to grails and is availble in Init.groovy as of 1.0.3
    // see http://jira.codehaus.org/browse/GRAILS-2663
     
    argsMap = [params: []]
     
    target(parseArguments: "Parse the arguments passed on the command line") {
        args?.tokenize().each {  token ->
            def nameValueSwitch = token =~ "--?(.*)=(.*)"
            if (nameValueSwitch.matches()) { // this token is a name/value pair (ex: --foo=bar or -z=qux)
                argsMap[nameValueSwitch[0][1]] = nameValueSwitch[0][2]
            } else {
                def nameOnlySwitch = token =~ "--?(.*)"
                if (nameOnlySwitch.matches()) {  // this token is just a switch (ex: -force or --help)
                    argsMap[nameOnlySwitch[0][1]] = true
                } else { // single item tokens, append in order to an array of params
                    argsMap["params"] << token
                }
            }
        }
        event("StatusUpdate", ["Done parsing arguments: $argsMap"])
    }

    If you have this groovy script (userScripts/showParams.groovy):

    println "in showParams script, argsMap is: $argsMap"
    println "in showParams script, raw args are: $args"

    And call it with this command line:

    grails run-script-with-parms userScripts/showParams.groovy --foo=zazz -b=quux

    You’ll get this as a result with the args passed in:

    in showParams script, argsMap is: ["params":[], "foo":"zazz", "b":"quux"]
    in showParams script, raw args are: userScripts/showParams.groovy
    --foo=bar
    --foo=zazz
    -b=quux
  11. 2008/06/1Steve say:

    I tried your code to load my script, but my script wasn’t able to read existing entries in the database (which works when loaded into grails console).

  12. 2008/06/2tednaleid say:

    @Steve Did it give you some sort of error, or were the items just not found? If they weren’t found, I’d be sure that you’re calling the script with the right environment (noted in the comments above). If you’re getting an error, does the stuff mentioned above by Armin Heinzer fix things for you?

  13. 2008/06/11Steve say:

    Sorry for the delay. I ended up just running my script in the grails console. I’m not familiar enough with grails to try what was suggested by Armin.

  14. 2008/12/8Peter-Frank Spierenburg say:

    I’m trying to create a script to add new members to my webapp. I’m trying to invoke the MemberController’s save() method to save the new member. The script claims to have created the new member, and I can find the new member using Member.findAll(), but the member’s record doesn’t show up in the database (when I choose production). And when I run the script a second time, Member.findAll() only finds the newly created member, not any of the members I’ve already created.

    Peter.

  15. 2008/12/9tednaleid say:

    Peter, that sounds more like a problem with your member save code than the script. Are you sure it saved?

    If you open up a “grails console” and paste your script in there and run it, does it get saved in the DB?

    Make sure you try to “validate()” before saving to ensure that you have all of the required fields on your domain object. See the grails docs on validation for more details.

    Also, make sure that you’re running the script against the environment that you think you’re running it against. You can specify your environment as the first grails parameter:

    grails prod run-script userScripts/env.groovy

    You can see what environment is currently running by putting this in your script:

    println grails.util.GrailsUtil.environment

    If I save that to userScripts/env.groovy and run the above command it prints out “production”.

  16. 2008/12/9Peter-Frank Spierenburg say:

    Upon further examination, there appears to be some kind of time-delay between statements in the frails shell and SQL winding up in prodDB.log. If I kill the shell too early, no SQL gets logged, and the user is effectively not created. I suspect that what is going on is that the GANT script ends before the database layer has an opportunity to persist the data. I hope I don’t have to add a time delay to my GANT script to account for this. Is there some kind of synchronization method that I can call to ensure that save()d data are actually persisted?

    Peter.

  17. 2008/12/9tednaleid say:

    I’ve never seen that kind of behavior before. You could try putting “flush:true” in your save method to see if that fixes things.

    Also, if you’re not letting the script exit normally (but doing some sort of System.exit(0)) that could potentially interrupt things too.

  18. 2009/02/16Armin Heinzer say:

    I tested this script with Grails 1.1-beta3 and my script was always executed twice because the target paseArguments was called twice.

    I had to comment out line 12: depends(checkVersion, configureProxy, packageApp, classpath)

    This fixed my problem.

  19. 2009/04/21Gabriele Prandini say:

    is the first time i’m tryng to use a script inside a grails project

    I need to have a script that run has a “crono job” invoced by someone else

    so i want to set up a script that do something with domain object, so i suppose what i found in this page is what i wnat, correct?

    I just tried to do what is written here… but is not working

    I put the RunScript on the scripts folder
    then a script in a folder called “myScript”
    i tried this script

    Prova.groovy
    def chiamata = Chiamata.get(‘2002/00003/C’)
    println (“chiamata” + chiamata.id)

    then i try to execute, from the project directory

    grails run-script myScript/Prova.groovy
    and i get

    Welcome to Grails 1.1 – http://grails.org/
    Licensed under Apache Standard License 2.0
    Grails home is set to: C:\Programmi\Grails\grails-1.1

    Base Directory: C:\stuff\HelpDeskMobile
    Running script C:\stuff\HelpDeskMobile\scripts\RunScript.groovy
    Environment set to development
    Warning, target causing name overwriting of name default
    Warning, target causing name overwriting of name default
    Warning, target causing name overwriting of name parseArguments
    Done parsing arguments: [params:[userScripts/Prova.groovy]] …
    [groovyc] Compiling 1 source file to C:\Documents and Settings\gprandini\.grai
    ls\1.1\projects\HelpDeskMobile\classes
    Done parsing arguments: [params:[userScripts/Prova.groovy, userScripts/Prova.gro
    ovy]] …
    Before Compile …
    [groovyc] Compiling 1 source file to C:\Documents and Settings\gprandini\.grai
    ls\1.1\projects\HelpDeskMobile\classes
    Before classloader …
    Before setContext …
    Before loadApp …
    Error executing script RunScript: tried to access method org.springframework.web
    .context.support.WebApplicationContextUtils.registerWebApplicationScopes(Lorg/sp
    ringframework/beans/factory/config/ConfigurableListableBeanFactory;)V from class
    org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext
    java.lang.IllegalAccessError: tried to access method org.springframework.web.con
    text.support.WebApplicationContextUtils.registerWebApplicationScopes(Lorg/spring
    framework/beans/factory/config/ConfigurableListableBeanFactory;)V from class org
    .codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext
    at grails.spring.BeanBuilder.createApplicationContext(BeanBuilder.java:5
    10)
    at grails.spring.BeanBuilder$createApplicationContext.call(Unknown Sourc
    e)
    at _GrailsBootstrap_groovy$_run_closure1.doCall(_GrailsBootstrap_groovy:
    61)
    at RunScript$_run_closure2.doCall(RunScript:29)
    at RunScript$_run_closure1.doCall(RunScript:13)
    at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
    at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
    at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
    at gant.Gant.withBuildListeners(Gant.groovy:344)
    at gant.Gant.this$2$withBuildListeners(Gant.groovy)
    at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
    at gant.Gant.dispatch(Gant.groovy:334)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.processTargets(Gant.groovy:495)
    at gant.Gant.processTargets(Gant.groovy:480)

    and i get the same error even if i try with a inexisten file, as
    grails run-script myfoo/myfoo.groovy

  20. 2009/10/20Jean Barmash say:

    Now that grails has parseArguments included, the script does not need the last target (parseArguments). Having it in causes trying to run the script twice, actually.

    The script works great – thanks a lot. Using it with 1.2M3 with no problems.

  21. 2009/11/9Andrew say:

    I tried this and it executed the code which included creating and saving some domain classes, but nothing persisted in the database.

    BTW, the same code worked fine before when called from a web request.

    How does it know to do a commit and finish the transaction?

  22. 2009/11/9tednaleid say:

    @Andrew, does that same code work inside a console? That’s pretty much the same thing that this script executor is doing. Bootstraping the environment like it does for the console and then executing it and quitting.

    Are you sure that the environment that you’re loading up is one that isn’t using an in-memory database (or one that has create-drop specified in the datasource.groovy)?

  23. 2010/01/24Greg say:

    I’m another user who cannot get objects created by my script to persist to my DB with this method. Pasting my groovy script into the console yields the correct behavior: the new object I create is saved.

    I am using Grails 2.2 and HSQLDB in development mode but I changed DataSource.groovy to persist to a database named devDb. As I said, console does save the data there. Has anyone figured it out, or is there another method for running some Grails app logic from a Gant script?

    Thanks for this helpful blog!

  24. 2010/01/25Greg say:

    Oops, I meant Grails 1.2 of course!

  25. 2010/01/26tednaleid say:

    @Greg, I just gave it a shot and it seems to be working for me.

    I cleaned things up a little bit and put a sample test repo out on bitbucket that demonstrates the code working.

    Here’s the slightly updated RunScript.groovy that worked for me in grails 1.2.

    This is the script that it’s executing (along with the command at the top of the script to run).

    If you’re having problems getting things to persist, make sure that you’re running in an environment that persists data and that isn’t doing a drop/create on the schema (that’ll whack the stuff that you do).

  26. 2010/01/28Greg say:

    Ted, thanks, and I did make some progress in the meantime. I had already set up my DataSource.groovy not to delete, and the same code that does in fact persist data to disk when run in console would fail to do quite the same thing with RunScript. The data would get put in but the “ALTER COLUMN ID RESTART WITH” directives in my devDb.script did not increment, and so the SECOND time I would call my code from RunScript, it would give me a database error for the duplicate key it was trying to insert. Do you not see that behavior?

    My first attempt to fix it was to add the code Armin Heinzer added in another comment up above. When that didn’t work, I commented out the body of your configureHibernateSession() method and that did the trick, all the data is persisted and the restart counts are updated as well.

    I don’t have any many-to-manys so I hope I don’t have to dig in and find out WHY commenting out those lines helped me… anyway I’m able to do what I want now and for that I thank you very much!

  27. 2010/01/29Bernard say:

    hi Ted,
    Thanks for this very useful script! Unfortunately I ran into the same kind of problems on Grails 1.2 : it just doesn’t persist my objects. I’m running it on dev but with dbCreate = “update”. The code is very simple:

    def user = new User(userid: “hello”, firstName: “hhhh”, lastName: “ddd”).save()
    def u = User.findByUserid(“hello”)
    assert “hello” == u.userid

    The assert fails, there is nothing in the database. I tried Greg’s trick commenting out the configureHibernateSession(), that didn’t work either.
    I guess I’m doing something wrong. Any idea why the objects are not saved? Thanks!

  28. 2010/01/29tednaleid say:

    @Bernard, I don’t know what your domain class looks like, but you aren’t checking in your script that it actually saved successfully.

    The easiest thing to do is to change your save() to save(failOnError: true) so that if it isn’t saving because of a missing field/failed constraint, it lets you know rather than failing silently.

  29. 2010/01/29Bernard say:

    Thanks for the quick reply!
    I did put (failOnError: true) but no message comes up. Actually I have no constraints right now on the domain class, only that it needs a userid. Also when I run the same code from the console it works and the record is saved into the database.
    I have the autobase plugin activated, do you think it could matter?
    I will try removing it…

  30. 2010/01/29tednaleid say:

    @Bernard, if I were you I’d check out the sample bitbucket application that I noted a couple of comments up, stick your domain objects in it and see if your script runs. That minimal case might help you narrow things down.

  31. 2010/02/2Bernard say:

    hi Ted,
    I did what you said. Even though it works in dev with the in memory database, it does not work with oracle as test database.
    Even simplifying the code to the extreme, saving only an author does not work. I tried it in the console and that works.
    Your example createBook.groovy neither works in the console nor through run-script.
    I played around a couple of hours with different parameters like including or not the schema name, etc. nothing helped.
    As expected, in the log of the simple code that works from the console I get that:
    Hibernate:
    select
    hibernate_sequence.nextval
    from
    dual
    Hibernate:
    insert
    into
    author
    (version, name, id)
    values
    In all the cases that do not work (console or script) in the log, I always have the first part
    Hibernate:
    select
    hibernate_sequence.nextval
    from
    dual
    but never the second part with the insert.

    I’m not very experienced neither with grails nor groovy nor hibernate. I have done a lot of java, ibatis, rails, etc. so maybe I miss something crucial in grails that would explain why I don’t get it to work.
    My hope was to be able to migrate a legacy database to a completely new schema using grails and your script.
    I guess I have to give up! Anyway, thanks for your help and I will look at the problem again in a couple of weeks, maybe I find the obvious thing that I miss now… I will let you know.

  32. 2010/02/9dave say:

    It looks like the RunScript hibernate session does not flush all objects after the completion of the script.

    I added

    def sessionFactory = appCtx.getBean(“sessionFactory”)
    def session = SessionFactoryUtils.getSession(sessionFactory, true)
    session.flush()

    after the GroovyShell script was run, and at least now the objects persist to a database, but it would be nice to find a more elegant solution to this.

  33. 2010/02/24Xain say:

    Hi Ted, I tried the http://bitbucket.org/tednaleid/grails-run-script/src/tip/scripts/RunScript.groovy version with Grails 1.2.1 and I’m getting the following error:

    Error executing script RunScript: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script1.groovy: 1723: expecting ‘)’, found ‘9′ @ line 1723, column 330.
    1 error

    gant.TargetExecutionException: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script1.groovy: 1723: expecting ‘)’, found ‘9′ @ line 1723, column 330.
    1 error

    at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:331)
    at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
    at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
    at gant.Gant.withBuildListeners(Gant.groovy:344)
    at gant.Gant.this$2$withBuildListeners(Gant.groovy)
    at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
    at gant.Gant.dispatch(Gant.groovy:334)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.processTargets(Gant.groovy:495)
    at gant.Gant.processTargets(Gant.groovy:480)
    Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script1.groovy: 1723: expecting ‘)’, found ‘9′ @ line 1723, column 330.
    1 error

    at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:296)
    at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:143)
    at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:113)
    at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:125)
    at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:353)
    at org.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParserPlugin.java:96)
    at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:63)
    at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:249)
    at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:163)
    at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:820)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:513)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:489)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:466)
    at RunScript.executeScript(RunScript:46)
    at RunScript$_run_closure2_closure3.doCall(RunScript:31)
    at RunScript$_run_closure2.doCall(RunScript:30)
    at RunScript$_run_closure1.doCall(RunScript:15)
    at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
    … 10 more
    Error executing script RunScript: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Script1.groovy: 1723: expecting ‘)’, found ‘9′ @ line 1723, column 330.
    1 error

    Application context shutting down…
    Application context shutdown.

    Any clues? Thanks

  34. 2010/02/24tednaleid say:

    @Xain – that looks like a syntax error in the script your trying to run. To test it, I’d start up “grails console” and paste the entire contents of your script in the grails console window. See if that blows up anywhere (and make sure you don’t have a “9″ wherever it’s expecting a “)” )

  35. 2010/02/24Xain say:

    I managed to get it to work, but although I get OKs only (I’m validating the object after the .save() just like you), there are no entries in the DB.

    I added

    def sessionFactory = appCtx.getBean(“sessionFactory”)
    def session = SessionFactoryUtils.getSession(sessionFactory, true)
    session.flush()

    but I’m getting the exception:

    Error executing script RunScript: No such property: appCtx for class: Script1
    gant.TargetMissingPropertyException: No such property: appCtx for class: Script1

  36. 2010/03/12Neil say:

    Running a script or class at the command line is such a simple task and should not be so overly difficult to perform… (and there’s something ugly about using a Test to execute class methods just so “grails test-app” can be used at the command line).

    This script fit perfectly, and should be part of the Grails distribution. Thanks for sharing it!

  37. 2010/03/12Neil say:

    As Armin said above, I also had to comment out line 12: depends(checkVersion, configureProxy, packageApp, classpath) or the parseArguments block ran twice…

    Also, how can I pass the argsMap into a full blown class? I’m not running a script. Looks something like this:

    grails run-script-with-params grails-app/controllers/MyController.groovy –foo=bar

    …and this…

    Class MyController {
    def main = {
    println “argsMap is: $argsMap”
    }
    }

    …and I receive the error that argsMap doesn’t exist…

    Error executing script RunScriptWithParams: No such property: argsMap for class: CatalogController
    gant.TargetMissingPropertyException: No such property: argsMap for class: CatalogController

  38. 2010/04/24Ashish Ranjan say:

    nice work.
    Why dont u submit both (with and without argument scripts) scripts for inclusion in the next version of grails itself?

    Ashish Ranjan
    ashishwave@yahoo.com

  39. 2010/05/10corey_s say:

    Has anyone gotten this to work w/ grails-1.3rc2?

  40. 2010/05/10corey_s say:

    regarding grails 1.3:

    I got things working by simply adding:

    setDefaultTarget(‘default’)

    … to the latest bitbucket version of the script:

    http://bitbucket.org/tednaleid/grails-run-script/src/tip/scripts/RunScript.groovy

  41. 2010/05/17Vino say:

    Works like a charm. A missing new line in the createBook.groovy, but a great example nevertheless.

    Now all I need to figure out is to run it outside of grails… Has anyone tried this? Ted?

  42. 2010/05/18tednaleid say:

    @Vino Thanks, I’m glad you found it useful.

    I took a look at createBook.groovy, but I’m not seeing a missing newline anywhere. What am I missing?

    I’m also not sure what you mean by “run it outside of grails”, running it inside of grails is sort of the whole point :). Do you mean with just GORM? I haven’t tried that.

  43. 2010/05/18Vino say:

    Yes. Sorry. This is what happens when an elec engineer tries to use stuff he doesn’t totally understand. :)

    I am creating a small grails app which accesses a database. The database itself gets updated by some other source. I’d like to share the domain classes and utilize the power of GORM as much as possible even in the ‘external’ script so I don’t have to deal with schema ‘mismatch’.

    Idea is to create a script which can be used to update the database with a command line interface, while my grails app works flawlessly with the same back-end. You think its possible? I’d like to get there.

  44. 2010/05/18tednaleid say:

    Yep, that should be possible. If you google around for information around using GORM outside of grails, there should be a number of blog posts that pop up around it. If you apply that so that it runs that way with your script (and so that your GORM domain objects are part of your classpath when the script runs) it should work. I just haven’t tried it so I can’t give you more specific info, good luck!

  45. 2010/06/2Vladimir Grichina say:

    Hi Ted,

    Your latest script didn’t work on Grails 1.3.1, so I updated it a bit:
    http://gist.github.com/423119

    Would like to get comments from you, going to publish it in blog as well.

    Thanks,

    Vladimir

  46. 2010/06/3Vladimir Grichina say:

    As promised, blog post about updated version – http://www.componentix.com/blog/15

Write a comment: