Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreFor a long time, managing Grails dependencies simply meant putting them in your application's lib directory. Then came Grails 1.2 and the dependency DSL: you could finally declare your dependencies and have Grails automatically download them and make them available to your app. Great!
Now, Grails 1.3 has brought the dependency DSL to the realm of plugins.
As for the dependencies, some plugins include libraries you don't need or (even worse) break your application. With the dependency DSL, you can explicitly exclude problematic libraries.
Those are some of the reasons why this change might be important to you. So how do you use the new feature?
I'll assume that Artifactory is already installed and running - for details of getting to this stage, check out its website and in particular the "One minute Artifactory" screencast. At this point we have a local repository, but it's not serving any artifacts yet. Let's fix that.
I'm going to add the 'db-util' plugin and the 'commons-digester' library. You can try with any plugins or JARs you have available. Simply navigate to the 'Deploy' tab of Artifactory (having logged in with username "admin", password "password"), choose the appropriate files, and upload them. I grabbed the files:
$USER_HOME/.ivy2/cache/commons-digester/commons-digester/jars/commons-digester-2.0.jar $USER_HOME/.grails/1.2.1/plugins/db-util-0.4.zip
and added them via the Artifactory UI:
Note that the UI allows you to specify the target repository for the upload. I chose 'plugins-releases-local' for the 'db-util' plugin and 'libs-releases-local' for 'commons-digester'. Also, before committing the plugin artifact, I set its groupId to 'org.grails.plugins' and its artifactId to 'db-util' (the default values are both 'grails-db-util'). The 'org.grails.plugins' groupId is the one that Grails assumes for plugin dependencies. Note also how the artifactId doesn't include the "grails-" prefix.
Those two artifacts are now available locally to any of your Grails applications. Now we need to configure the repository and dependencies in our Grails application.
grails.project.dependency.resolution = {
...
log "warn"
repositories {
grailsPlugins()
grailsHome()
mavenRepo "http://localhost:8081/artifactory/libs-releases-local/"
mavenRepo "http://localhost:8081/artifactory/plugins-releases-local/"
grailsCentral()
}
plugins {
build "org.grails.plugins:db-util:0.4"
}
dependencies {
compile "commons-digester:commons-digester:2.0"
}
}
So, in the repositories section you add a mavenRepo entry for each "repository" exposed by the Artifactory server. Note that in this case, we add both the 'libs-releases-local' repository and the 'plugins-releases-local' one.
The new addition to the DSL is the plugins section, which is (unsurprisingly) for declaring Grails plugins. It has exactly the same syntax as the dependencies section. So, 'db-util' is declared under plugins and 'commons-digester' is declared under dependencies.
That's all you have to do. If you now execute grails run-app, you'll see the some output like this:
... Resolving dependencies... Downloading: http://localhost:8081/artifactory/libs-releases-local/commons-digester/commons-digester/2.0/commons-digester-2.0.pom ... Download complete. Downloading: http://localhost:8081/artifactory/libs-releases-local/commons-digester/commons-digester/2.0/commons-digester-2.0.pom.sha1 ... Download complete. ... Downloading new plugins. Please wait... ... Downloading: http://localhost:8081/artifactory/plugins-releases-local/org/grails/plugins/db-util/0.4/db-util-0.4.pom ... Download complete. Downloading: http://localhost:8081/artifactory/plugins-releases-local/org/grails/plugins/db-util/0.4/db-util-0.4.pom.sha1 ... Download complete. Downloading: http://localhost:8081/artifactory/plugins-releases-local/org/grails/plugins/db-util/0.4/db-util-0.4.zip ... Download complete. Downloading: http://localhost:8081/artifactory/plugins-releases-local/org/grails/plugins/db-util/0.4/db-util-0.4.zip.sha1 ... Download complete. Installing zip /home/pal20/.ivy2/cache/org.grails.plugins/db-util/zips/db-util-0.4.zip... ...
The 'db-util' plugin is installed and the 'commons-digester' JAR included on the classpath. Simple.
If you run into issues with the dependency resolution, then you can dial up the logging by replacing the log "warn" line in BuildConfig.groovy with log "info" or even log "debug".
Of course, sometimes you will want to host your own plugins or customised/patched versions of public one. The existing release-plugin command only works with old-style Subversion repositories, so what can you do?
Install this in your plugin project, add the following entry to your BuildConfig.groovy file:
grails.project.dependency.distribution = {
remoteRepository(id: "pluginSnapshots", url: "http://localhost:8081/artifactory/plugins-snapshots-local/") {
authentication username: "admin", password: "password"
}
}
and then run
grails maven-deploy --repository=pluginSnapshots
Voila! Your plugin will be deployed to the local Artifactory 'plugins-snapshots-local' repository with a groupId of org.grails.plugins. Note that the value you pass for the --repository argument should match the 'id' of a remote repository defined in the grails.project.dependency.distribution closure in BuildConfig.groovy.
You can fine tune the deployment, for example by using a pom.xml file with a <distributionManagement> element or by adding a groupId property to the plugin descriptor, but the basic steps are all straightforward.
All that's left to explain is where the dependency information is held. For example, the dependencies for normal artifacts (such as JAR libraries) are stored in a metadata file like pom.xml. Grails plugins are different. Their JAR dependencies are inside the zip package in a dependencies.groovy file. As for plugin dependencies, you define these as before in the dependsOn field in the plugin descriptor. These are then translated into dependency declarations in your plugin's generated pom.xml file (which is stored alongside the plugin zip file in the repository).
And that really is all there is to it. You can now provide your own, easy-to-manage Maven-compatible repository so that your team members no longer have to hit the internet every time they need a plugin or dependency. You can also inject some consistency into your projects by controlling which versions of Grails plugins are available. And you can easily patch public plugins and make those versions available to your team locally, while you wait for the fixes to make it into an official release.