Abstract

Grape (The Groovy Adaptable Packaging Engine or Groovy Advanced Packaging Engine) is the infrastructure enabling the grab() calls in Groovy, a set of classes leveraging Ivy to allow for a repository driven module system for Groovy. This allows a developer to write a script with an essentially arbitrary library requirement, and ship just the script. Grape will, at runtime, download as needed and link the named libraries and all dependencies forming a transitive closure when the script is run from existing repositories such as Ibiblio, Codehaus, and java.net.

TimeFrame

The prototype is ready for inclusion into the trunk immediately, however the principal dependent library used (Apache Ivy) is a SVN snapshot.  We should at least wait for a Beta 2 release and preferably for an RC release of the library before merging into trunk.  That makes it a possible 1.6 candidate, and more likely a 1.7 candidate.

General Requirements

Specification

Module versioning model.

Grape follows the Ivy conventions for module version identificaiton, with naming change.

Code Level Support

Annotation

One or more groovy.lang.Grab annotations can be added at any place that annotations are accepted to tell the compiler that this code relies on the specific library. This will have the effect of adding the library to the classloader of the groovy compiler. This annotation is detected and evaluated before any other resolution of classes in the script, so imported classes can be properly resolved by a @Grab annotation.

import com.jidesoft.swing.JideSplitButton
@Grab(group='com.jidesoft', module='jide-oss', version='[2.2.1,)')
public class TestClassAnnotation {
    public static String testMethod () {
        return JideSplitButton.class.name
    }
}

An appropriate grab(...) call will be added to the static initializer of the class of the containing class (or script class in the case of an annotated script element).

TODO: How do we add a grab annotation to straight scripts? The current workaround is to annotate something in the script that can accept an annotation, like a method or parameter.

Method call

Typically a call to grab will occur early in the script or in class initialization. This is to insure that the libraries are made available to the ClassLoader before the groovy code relies on the code. A couple of typical calls may appear as follows:

// random maven library
groovy.grape.Grape.grab(group:'com.jidesoft', module:'jide-oss', version:'[2.2.0,)')
groovy.grape.Grape.grab([group:'org.apache.ivy', module:'ivy', version:'2.0.0-beta1', conf:['default', 'optional']],
     [group:'org.apache.ant', module:'ant', version:'1.7.0'])

// endorsed Groovy Module
// FUTURE grab('Scriptom')

* grab(Object self, String module),- grab(Object self, Map attrs), and grab(Object self, Map attrs, Map... dependencies) will be added to the DGM so that references to the backing Grape classes will not be needed. These will be proxies to the main Grape class calls.

grab(HashMap) Parameters

There are two principal variants of grab, one with a single Map and one with an arguments Map and multiple dependencies map. A call to the single map grab is the same as calling grab with the same map passed in twice, so grab arguments and dependencies can be mixed in the same map, and grab can be called as a single method with named parameters.

There are synonyms for these parameters. Submitting more than one is a runtime exception.

Arguments Map arguments

Tool level support

GroovyStarter

GroovyStarter has been enhanced with an additonal --grab option. All three main arguments are required (group, module, version). Resolved jars will be added to the RootLoader. These modules will be resolved prior to the main class call.

LoaderConfiguration conf files

LoaderConfiguration has been enhanced with an additional 'grab' line option, where the option is followed by all three arguments (group, module, version). Resolved jars will be added as though they were specifically mentioned by a 'load' line option. These lines are similarly subject to property replacement as 'load' lines are.

<groovyc> support

The GroovyC ant task has been enhanced with <grab> child elements. The attributes group, module, and version specify the module to grab.

TODO: currently this doesn't work when fork='true'

File Level View

The downloaded modules will be stored according to Ivy's standard mechanism with a cache root of ~/.groovy/grape

Command Line Tools

grape install <groupId> <artifactId> [<version>]

This installs the specified groovy module or maven artifact. If a version is specified that specific version will be installed, otherwise the most recent version will be used (as if '*' we passed in).

grape list

Lists locally installed modules (with their full maven name in the case of groovy modules) and versions.

grape resolve (<groupId> <artifactId> <version>)+

This returns the file locations of the jars representing the artifcats for the specified module(s) and the respective transitive dependencies.

Motivation

The motivation for introducing Grape into groovy is to resolve the library and module proliferation problem we are encountering. As a general purpose language Grape is suitable for a lot of wildly variable tasks. Providing groovy ways to do those things can crate 'bloat' because a large number of classes that are

Rational

Credit for coming up with the name Grape goes to Jörg Staudemeyer and grab Andres Almiray.

Use of Maven Repositories

Maven is big, there are tons of Java libraries that are already deployed in a well-known infrastructure. Because almost all(question) of these are straight Java they are all usable in Groovy out of the box.

Use of Ivy

Backward Compatibility

GroovyStarter does do some existing library management, namely loading every singe jar in ~/.groovy/lib into the RootLoader. With Grape installed such behavior can continue, and is merely duplicate effort with no adverse implications. In the 2.0 timeframe we may want to look into deprecating or removing the auto-include of the ~/groovy/lib directory.

Reference Implementaion

A 0.1.0 protptype is available. This shows the grab(...) method, the @Grab annotation, and command line tools. Examples are available in subversion in src/examples, except for the annotation, where the best examples are in the test class.

This version may conflict with Gant, only one of the Ivy files should exist under $GROOVY_HOME/libs. If the beta-1 jar is left in place then Grape may not work.

Future Directions

We may want to increase the kind of repositories that Grape can handle from simple Ivy and Maven repositories to other areas such as OSGi Repository Bundles , JNLP (WebStart) files and JSR-277 JAM files.