Tuesday, May 8, 2012

Grape: adding a repo to the ivy configuration

Grape is a great thing. It’s one of my favorite features in groovy. It makes groovy script distribution so easy and painless. You want to use your groovy script on a new machine? Install groovy (if not already done) on the other machine and copy the script to the new machine. The script and all declared dependencies will be downloaded for you and the script is ready to run. What a timesaver.

@Grab(group='mycompany.com', module='awesome-lib', version='1.2')

This statement specifies a dependency to a library that your groovy script depends on. No need to copy this jar and all transitive dependencies manually to your machine. No need to make it manually available in the classpath. You know maven, gradle and ivy. They do the same job during build time. Grape provides the same dependency resolving functionality in the runtime scenario. No worries about missing dependencies anymore.

What happens if a required dependency is part of a not-so-famous or a company internal repository? Grape has a solution for it! You specify the repository with a Grape annotation and tell the dependency resolver to consult your company repository in order to resolve dependencies.

The following statement will add a repository named ‘my_unknown_repository’ and a root URL ‘http://repo.mycompany.com’ to the list of resolvers.

@GrabResolver(name='my_unknown_repository', root='http://repo.mycompany.com')

In case that you have a company internal repository (which also acts as a proxy to the outside world) and you always want to consult this repository without always remembering the GrabResolver annotation for every script you write, there is another way of specifying the repository. This option is less flexible, but it saves this one line in every script and probably makes more sense in a larger context like companies. To add your repository permanently to the resolver list, I recommend to obtain a copy of the configuration file that Grape uses to configure the underlying ivy to perform the heavy-lifting.

Grape uses a specific configuration that can be found in the groovy-x.y.z.jar. In order to customize the configuration, we need to create a grapeConfig.xml and add our repository there. But how does the content of the file look like? To preserve the existing configuration, we get a copy of the original config file from the groovy.jar.

Let’s jump to the command line (I assume that java’s jar is in the search path and /path/to/groovy exists):

jar -xf /path/to/groovy/lib/groovy-1.8.6.jar groovy/grape/defaultGrapeConfig.xml

This command extracts the defaultGrapeConfig.xml to the current directory. Open this file with your favorite editor and you will probably see something like this:

<ivysettings>
  <settings defaultResolver="downloadGrapes"/>
  <resolvers>
    <chain name="downloadGrapes">
      <filesystem name="cachedGrapes">
        <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/>
        <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"/>
      </filesystem>
        <!-- todo add 'endorsed groovy extensions' resolver here -->
      <ibiblio name="codehaus" root="http://repository.codehaus.org/"   m2compatible="true"/>
      <ibiblio name="ibiblio" m2compatible="true"/>
      <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/>
    </chain>
  </resolvers>
</ivysettings>

Now go ahead and copy one of the <ibiblio… /> lines and add your repository configuration. Finished with editing? Save the file as grapeConfig.xml in ~/.groovy/. From now on Grape will search your repository every time there is a dependency to resolve. If you want Grape to use only your repository, because it’s caching downloaded dependencies, you should remove all <ibiblio… /> lines, except the one for your repository.

Additional documentation about Grape can be found here.