Hacking Grails Source Day 3 (Where I Realize The Perils Of Not Clearing The Ivy Cache After Building)
My last post provided a recipe for downloading and modifying the Grails sources. I wrote that post immediately after I managed to get my deliberately introduced hack (an exception that stopped page rendering in its tracks) to manifest itself. Next I modified the hacked source slightly (changing the message passed to the RuntimeException constructor), and I got a little surprise: none of my changes seemed to take effect. To track the problem down I spent several hours crawling through the source with my debugger (this post will explains how I attached all the necessary Grails and Spring sources so I could see what’s going on.) I also applied my standard tricks for for clearing out the cruft from prior builds.
- I blew away $HOME/.grails completely (this is useful for clearing out cached plug-ins, among other things.)
- I also blew away my sample project and built a new project from scratch.
I still failed to see the new Exception messages that I built the Grails source with. Only after blowing away $HOME/.ivy2 — the Ivy cache –did my changes begin to take effect.
So that’s the trick: after building a new distribution using
gradlew assemble
you should blow away $HOME/.grails and your Ivy cache to ensure the changes take effect.
Some Notes On How The grails run-app Command Eventually Invokes the Ivy Resolver
Below you will find some of the notes I took on what happens under the hood in Grails when you issue the grails run-app command. I’m not going to comment on these extensively. If you set some breakpoints in the referenced methods and read my notes as you go this will probably help you understand the flow in a shorter amount of time than I required.
Before you read these notes, I suggest you read the Bootstrap chapter of Dmitriy Kopylenko’s evolving open source book on Grails Architecture.
Now, without further ado, here they are… the notes:
$GRAILS_HOME/bin/grails [shell script]
Invokes ->
org.codehaus.groovy.grails.cli.GrailsScriptRunner
GrailsScriptRunner.executeCommand("RunApp")
->
GrailsScriptRunner.
callPluginOrGrailsScript(COMMAND = "RunApp")
Processing steps
1) BUILD CLASS LOADER
This method builds up the class loader used to run Gant.
It's the root loader plus all the Grails application's
compiled classes (i.e., everything that ends up
in /target/classes.
callPluginOrGrailsScript() invokes ->
GrailsScriptRunner.getCLassLoaderUrls()
invokes ->
BuildSettings.getBuildDependencies()
BuildSettings sets up project paths and
other build settings that the user
can change when running the Grails commands.
[ this class reads directives from
BuildConfig.groovy ]
getBuildDependencies()
invokes ->
IvyDependencyManager.resolveDependencies()
invokes ->
org.apache.ivy.core.resolve.ResolveEngine.
resolve()
uses IVY cache in $HOME/.ivy2
2) SET THE CONTEXT CLASS LOADER FOR THE CURRENT THREAD
3) SEARCH KNOWN LOCATIONS FOR SCRIPT CORRESPONDING TO COMMAND
Try to find the script to use to run the given command,
...searching through:
$GRAILS_HOME/scripts,
/scripts, and
$HOME/.grails/scripts
























on June 20th, 2010
[...] next post walks you through some of the snags that you might encounter if you make subsequent changes to the [...]