Grails 2.0 #1: Gradle for the win?

Ever since I attended a Gradle course, I’ve been rather obsessive about it. In particular, I’ve been looking at integrating Grails into Gradle builds. The early result was a straightforward Gradle plugin that allows you to build Grails projects. I’ve explained how to use it in a previous post, so I won’t talk about that here. It works, but it bothers me that the plugin delegates to the Grails build system. That interaction is always going to be anaemic and will almost certainly frustrate any Gradle power users. But is there any other approach that can work?

The problem

Grails has a custom build system based on Gant that has evolved over the years. The nature of the build and its interaction with Grails plugins means that it’s very difficult to integrate well with other build systems. It does its own dependency management (although it does delegate the grunt work to Ivy) and it has its own event system.

The trouble is, the build is definitely getting more bloated and complex as features are added. In fact, many of those features, such as dependency management, distinct compile/test/runtime classpaths, and artifact publishing, are built into a tool like Gradle. So we’re basically reinventing the wheel to some extent. And I have to admit that Gradle’s API is far more robust and flexible than the Grails build system.

This got me thinking: would a native Gradle build for Grails projects work? After all, build is not one of Grails’ core competencies. Why not leave it to a dedicated tool if that tool can handle Grails’ special requirements? Graeme and I had thought about doing this some time ago, but decided against the move. Gradle was still young and didn’t seem to offer enough benefits. Times have changed though.

My next thought was this: what is a Grails project if not a Groovy WAR project with a rather unique directory structure? If Gradle can handle that directory structure, why not use its standard compile tasks? Doing so would mean that other Gradle plugins would also work with Grails projects.

The solution

On that Gradle course, I discovered a Gradle feature that really sold me on its potential as a build tool for Grails projects: source sets. These are arbitrary groupings of source files that can pretty much manage any directory structure you can throw at them. Even a Grails project. All I had to do was create a test Grails project with a Gradle build, apply the ‘groovy’ plugin, and configure the source sets. Next thing I knew, I could compile a Grails project. Whoohoo!

If only everything was so simple. Trying to run a Grails application proved to be a far tougher challenge. This required compilation and loading of all installed Grails plugins, including the core plugins. On the bright side, I had an opportunity to create a build-specific plugin manager that didn’t have to worry about runtime stuff. This meant a great simplification of the code.

The result of all this work is another Gradle plugin, although this one hasn’t been published yet. It’s in a very raw state at the moment, and I want to avoid confusion with the existing Gradle plugin I mentioned at the beginning of the post.

About the plugin

So how does this plugin work? The core of it is the grails.build.plugin.GrailsPlugin class, which is the entry point for the plugin. It does several things of note:

  • apply the ‘groovy’ and ‘war’ plugins to the project;
  • configure the source sets;
  • sets up some extra dependency configurations; and
  • creates a whole bunch of specialist Grails tasks and creates the dependencies between them.

The most significant tasks are:

  • buildData – instantiates BuildSettings and loads the build configuration
  • buildPlugins – builds the project’s installed Grails plugins and loads them
  • generateWebXml – generates the web descriptor to ./web-app/WEB-INF/web.xml
  • generateApplicationContextXml – generates the root application context descriptor to ./web-app/WEB-INF/applicationContext.xml
  • packageI18n – copies the i18n resource bundles and converts them to ASCII if required
  • run – launches the configured servlet container

As you can see, the plugin already handles Grails plugins, although there is still much that doesn’t work. The fact that the plugin can fully build plugins of various types and add their dependencies and classes to the appropriate classpaths is a big deal though. This just doesn’t happen with the current Grails build system.

Another really neat feature is that Grails plugins can provide their own build files and Gradle plugins. You can see an example in the Jetty plugin that’s packaged in the root of the grails-build-x project. This is incredibly powerful stuff because it means that the Grails plugin can have full access to the Gradle build and do pretty much anything! For Jetty, this means adding the container starter classes to the servletContainer configuration and adding its dependencies to the project’s runtime classpath. But pretty much anything is possible.

The current run task demands some extra requirements of servlet container plugins, so that standard ones won’t work. However, the custom Jetty plugin I referred to earlier can also be used in a normal Grails project with the Grails build system. That means a plugin author can add features that help it integrate with the Gradle plugin without breaking normal Grails projects!

So what does it all mean?

The Grails build system evolved out of a failure on the part of existing build tools to provide a solution to building Grails projects, particularly once plugins were introduced. At the time, I think Gradle was still an idea in the air. Since then, the build system has grown in features and complexity, and it works pretty well.

Now, though, I think it’s time for it to retire. It doesn’t make sense for Grails developers to spend a lot of their time on build stuff when another tool is now available that will do most of the work itself. The build system also doesn’t play particularly well with other build tools, which can make adoption in the enterprise rather tricky. And a clean room implementation means clearing out a lot of cruft and being able to resolve some outstanding and difficult problems.

The great thing about the new Gradle build is that it can be developed in parallel to the Grails 1.x line. And if it makes it into Grails 2.0 as the build system, then hey, the plugin authors have already prepared and tested their plugins for it. Certainly my hope is that Gradle forms the core of the build system for Grails in the future. Fingers crossed!

9 thoughts on “Grails 2.0 #1: Gradle for the win?

  1. Wolfgang Schell

    Hi Peter,

    great stuff, keep it going.

    What I would like to see is the ability to compile source files, which can be used in the scripts provided by Grails plugins. The current build system does not distinguish between build-related code (other than scripts) and application code.

    Regards,

    Wolfgang

  2. Mark Smithson

    Excellent.

    Would be great to be able to use a build system for grails with the power to go beyond the “convention” defaults provided by grails. In particular a properly configurable dependency resolution system as provided by gradle….

    Not sure why Grails 1.2 did not use the Gradle dependency stuff and implemented it’s own DSL (based on gradle’s one, but a lot less powerful).

    Will follow this with great interest.

    Mark

  3. Peter Post author

    @Wolfgang This is tricky even with Gradle because I don’t think you can add to the build classpath once the build script has started. So you can do it from buildSrc or the buildscript closure, but not from plugins. I’m checking up on that though.

    However, you do have the power to separate your code into build, runtime, and test stuff simply by adding an extra source set. For example, the grails-x plugin adds a “plugin” source set in which you can add build related code, in particular a Gradle plugin implementation. Just put the code in an src/plugin directory and away you go. In this case, the grails-x plugin will load your plugin code and execute, but the classes won’t be included in the project’s compile or runtime classpaths.

    In other words, it’s possible, but you have to manage the classpaths and class loading yourself at the moment.

    @Mark Grabbing the Gradle dependency stuff without simply using the whole of Gradle would, I suspect, have been too much work for little reward. I don’t know for sure, but Gradle’s dependency management is probably tightly integrated into its execution model and API. That said, I’m not sure if anyone looked closely at it as a potential solution.

    Thanks all for the positive feedback. Glad I’m not a hermit with crazy ideas just yet 🙂

  4. Davide Cavestro

    Could you please update us on the status of the grails-build-x plugin? (cause it’s a GREAT idea!!!)

  5. Peter Post author

    It’s in limbo at the moment, but will probably form a starting point for Grails 2.0, which is switching to Gradle for its build system. Version 2 is currently scheduled for end of 2011.

Leave a Reply

Your email address will not be published. Required fields are marked *