Mark Derricutt's Disturbing Thoughts

Dependency Scope with Ivy

posted Monday, 25 September 2006

As we're starting to give our development environment a much needed update at ${work} I've been recently revisiting my usage of the Ivy dependency manager on my project and comparing it with the often hated Apache Maven (or at least the Maven Tasks for Ant).

I've not really used Maven beyond compiling Wicket and a few other projects and havn't had any of the grief that seems to plague alot of people, maybe I'm just lucky...

Anyways, one element I like from Maven over Ivy is the scope of a dependency:

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.4</version>
  <scope>provided</scope>
</dependency>

Having the ability to identifying a dependency as being provided by a container or a test only dependency is great for keeping a build file lean and clean, the only problem is that Ivy doesn't seem to have a similar concept.

Ivy Configurations

Ivy does however have a flexable system for grouping dependant artifacts into groups, or configurations. Ivy Configurations are defined in your ivy.xml file:

<configurations defaultconfmapping="runtime->runtime(*);test->test(*);compile->compile(*)">
  <conf name="compile" description="Build Time dependencies"/>
  <conf name="test" description="Test Time dependencies"/>
  <conf name="runtime" description="Run Time dependencies"/>
</configurations>

This defines three configurations to be used by your application. With Ivy - a module's artifacts can belong in one or more arbitrary configurations such as jdk14, or jdk15, by requesting the jdk14 configuration Ivy will deliver a subset of a dependencies artifacts that only work under Java 1.4. This differs somewhat from Maven's "one dependency - one artifact" approach where an additional <classifier> identifier can be used to distinguish dependencies.

An Ivy artifact's configuration defines which of our configurations it belongs to, and also which configuration we want to use, however with a long list of dependencies we don't really want to keep repeating ourselves - so the defaultconfmapping attribute can be used to Ivy some defaults.

<dependencies>
  <dependency org="testng" name="testng" rev="5.2" conf="compile -> jdk15"/>
  <dependency org="sun" name="jsp-api" rev="2.0" conf="compile"/>
  <dependency org="hibernate" name="hibernate" rev="3.1.3" conf="runtime, standalone -> runtime(*)"/>

The above ivy.xml dependency snippet defines three dependencies:

  1. The testng dependency belongs in our compile configuration with an upstream jdk15 configuration being used.

  2. The jsp-api dependency is also in the compile configuration but defines no custom upstream, so gets our default compile->compile(*) mapping which means "use the compile configuration from the dependency, but if it doesn't have one - use the * (default) configuration".

  3. The hibernate dependency entry lists itself in two locally defined configurations, with one common upstream.

These configuration definitions can now be used by your Ant build.xml to provide FileSet and Path objects to your build:

<ivy:cachefileset setid="files.ivy.libs.runtime" conf="runtime"/>
<ivy:cachepath pathid="path.ivy.libs.runtime" conf="runtime"/>

The fileset and path variables are now available to be used in calls to <javac> and <jar> and let you keep specific dependency details away from the actual build file.

Powered by Bleezer

tags:          

links: digg this    del.icio.us    technorati    reddit




1. Buzzterrier left...
Saturday, 24 May 2008 12:20 pm

Thx. This is a big help. The Ivy site has a lot of info, but they do not really cover confs that well. I knew they had some similarities with mvn scope but could not for the life of me figure them out!