Dependency Management with Ant and Ivy

January 17th, 2008

One of my long-standing complaints with Ant is that project dependency management is non-existent in the core Ant distribution. Many will quickly point to the Maven Ant tasks, but I’ve never been really fond of them for one reason or another. The other advice I often get is to use Ivy, but even after several attempts, I had never gotten Ivy to work. With the recent release of 2.0 beta 1, though, I thought I’d try again, and I’m glad I did. Not only have I gotten it to work for me, but I was also able to successfully configure custom resolvers. Below is what I had to do to migrate the Mojarra Scales dependency management to Ivy.

Using Ivy requires, at least in the way I’m using it, two new files, ivy.xml, which defines my dependencies, and ivysettings.xml, which configures my custom resolvers. The usage from my Ant build file is actually pretty simple, so we’ll start there:

You will also need to define these properties somewhere:

But what’s going on here? The -download-ivy target, simply downloads the Ivy jar and installs it in the target directory, lib/build in Scales’ case. Next, -install-ivy tells Ant how to find the Ivy tasks. Finally, in the update target, we tell Ivy where to find the settings (which we’ll look at in a moment), and then we tell Ivy to download the dependencies.

But what’s that pattern all about? This, I think, is a pretty interesting aspect of Ivy. Unlike Maven (and the related Ant tasks), the files aren’t just downloaded into a local repo and left, exposed to the build system through some sort of path or fileset reference. Ivy does download and cache the artifacts, but it also copies those to a directory in one’s project (at least, that’s how I have it set up ;). The pattern tells Ivy to copy the files a directory named after the configuration (more on that in a moment) under the lib/ directory, using an artifact-version.ext file name structure. It is then up to me to create a classpath or fileset reference from those files, and I think I like it that way. So, what’s this “configuration” I mentioned? For that, let’s turn our eyes to ivy.xml.

The ivy.xml for Scales looks like this at the moment:

Let’s take that one section at a time. The first element we see is info, and I’ll be honest here: I’m really not sure what that’s for at the moment. I think it may be related to publishing (or installing, in Maven parlance) project-specific artifacts to a repository somewhere, but don’t quote me on that. The next section is where we define “configurations,” which seem to be roughly analagous to Maven’s scope’s, but completely configurable and arbitrary. I have defined five configurations:

  • build: Jars need only for the build environment<./li>
  • javascript: This is an unusual one, but I use this only for the YUI files (currently) to make extracting the files easier later in the build process
  • applet: Jars which need to be bundled for use with the applet
  • compile: Jars needed only for compilation, API classes, for example
  • test: Jars needed for testing

Take note of the extends attribute. It works just like you probably think it does: since compile extends applet, it will get all of the artifacts defined for it, as well as those defined for applet. Given how Ivy (is configured to) handle dependencies, that means you’ll get two copies of some of those artifacts, but I’m OK with that.

Next in the file is the list of dependencies, which is pretty straightforward. The org maps to Maven’s groupId, the name maps to artifactId, rev maps to version, and conf maps to scope in Maven terms. Please don’t ask what that odd “->*” is there for, as I don’t understand that fully yet. All I know is that it won’t work without it. :)

Next up is ivysettings.xml:

One of the great things about Ivy 2 is that is configured to look at Maven repos by default. For Scales, though, I need some artifacts from the java.net Maven repository. To enable that, I have to define a custom resolver, which we see in the resolvers/chain elements. The chain resolver instructs Ivy to try one resolver after another to find the current artifact, with the returnFirst attribute telling Ivy to bail out as soon as a resolver that locates the artifact. Inside the chain, I instruct Ivy to use the ibiblio repository first. I then configure both the Maven 1 and Maven 2 java.net repositories. To do that, I configure additional instances of the ibilio resolver, but I change the root URL for the repository. In the case of the Maven 1 repository, I describe the pattern needed to find the artifact, as well as telling the resolver that the repository is not Maven 2 compatible. Finally, I create a URL repository, called “sourceforge,” which I will use to resolve my YUI dependency.

With all of that in place, I can issue an ant update from the command line, and sit back and watch Ivy checking the configured repositories for my dependencies. It may seem like a lot to configure for dependencies, but Ivy is certainly better than the homegrown dependency management schemes I’ve seen (and devised), and is certainly less intrusive than migrating wholesale to Maven. While I am coming around on Maven 2, this will be a great tool for those projects that I can’t (or won’t) migrate.

Technorati Tags: ,

Popularity: 100% [?]

7 Comments

  1. steve says

    Jason,

    I’m also trying to add YUI components to my ant/ivy based project.

    How did you add YUI to your repository? Did you just zip up the entire build directory, or did you break out the build components?

    I’d like to just define ivy dependencies for only those YUI components that I use.

    Any suggestions would be greatly appreciated.

    Thanks!

    January 29th, 2008 | #

  2. jason says

    Steve,

    I just had Ivy download the distribution from Sourceforge using the resolver above. Once Ivy was finished, I then unzipped the archive and moved things where I wanted them:

    As you can see, though, I’m copying everything. That can be easily modified to get just certain parts, but things get trickier if you want just the full, minimized, or debug versions and not the others, which is why I ship it all. At some point, I may add support for changing which version of the JS/CSS file is downloaded. We’ll see.

    January 29th, 2008 | #

  3. steve says

    I would definitely be interested in seeing the later if you get around to it.

    At this point at least, I’m only using the YUI DataTable, so I’d rather not include everything.

    Thanks for the quick response!

    January 29th, 2008 | #

  4. Xavier Hanin says

    Very good post, Jason! I’ll add a link from Ivy site.

    One small tip about your settings: you can use the module settings instruction to tell Ivy to use one resolver for a particular organization/module/whatever:
    http://ant.apache.org/ivy/history/latest-milestone/configuration/module.html

    I’d suggest moving your sourceforge resolver out of the chain, and tell Ivy to use it only for yui organization. This will improve the performance when you mistype a dependency, Ivy won’t search it on sourceforge which is probably pretty slow.

    About YUI, downloading directly the zip to unzip it is a nice solution. However I’d suggest setting up your own repository to put YUI files as modules, if you want better performance. Ivy being language agnostic, it can resolve dependencies on “javascript modules”. Steve, if you need help on how to do this, I suggest joining Ivy mailing list and ask.

    February 7th, 2008 | #

  5. jason says

    Xavier,

    Thanks for the tips. I’ll look into that. This is really my first big thing with Ivy, so I obviously have much to learn. I don’t if it’s just me or not (and it likely is), but I’ve had *MUCH* better success in getting v2 to work than I did with v1, so I’m just now finally getting into it. :)

    February 7th, 2008 | #

  6. Xavier Hanin says

    Ivy 2 has *MUCH* better maven 2 support than 1.4 had, that’s probably the reason it’s easier :-)

    February 9th, 2008 | #

  7. Rob Diana says

    Jason

    Excellent intro for ivy and ant. We had used luntbuild at a previous job because
    we couldn’t get ivy and ant to work the way we wanted. You have been bookmarked/stumbled/etc.

    February 9th, 2008 | #

Sorry, the comment form is closed at this time.

JSFOne Speaker Image
With many thanks to Kaushal Sheth
`