views:

293

answers:

2

I have a problem with a build where I have to resolve non-standard artifacts through Apache Ivy.

Problem:

  • I have dependencies on two artifacts (a.jar and a-lib.jar).
  • The two dependencies come only as part of a single installer (a_installer.jar).
  • The installer can be downloaded, the embedded artifacts themselves not.
  • It's possible to manipulate the installer to unpack the needed dependencies.

Requirements:

  • I have to resolve/download the artifacts during the build (I cannot keep the installer or the extracted artifacts with my code).
  • I cannot use a repository to store the extracted artifacts.
  • Subclassing/Extending Ivy/whatever is perfectly fine.

Has anyone solved a similar problem, or some helpful information to share?

Or maybe I'm approaching the problem in the wrong way? From what I found so far on the web, people seem to use Ivy just to download files and post-process them manually (with Ant/whatever) after the fact, and not actually resolving more complicated dependencies within Ivy.

Thanks

PS: I don't care whether the installer is also put into the ivy download cache, but I would like to download the installer only one time (and not for both dependencies).

A: 

I think this is very straightforward: 'ivy:retrieve' a_installer and then unzip a.j and a-lib into your lib directory (or wherever you want it). This should be easily to do with ant?

I have to wonder if there is some complication you haven't mentioned that prevents you from doing this.

Zac Thompson
A: 

The problem with a call to "ivy:retrieve" is that you need to also add an "artifact" tag in your ivy.xml (complete with URL) in order to retrieve a dependency not found in a Maven respository...

I don't like this for two reasons

  1. The ivy.xml should just declare your dependencies, not their locations.
  2. Need additonal custom logic in the build.xml to handle the 3rd party package

Ideally it should be your repository settings that decide how to download the various jars, that is why I like the packager resolver. Even if the library I want is not in Maven, I can configure ivy to handle it.

The following is an example of turning the jreleaseinfo project into an ivy dependency (hosted in sourceforge, I couldn't find it in Maven)

ivy.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<ivy-module version="2.0">
    <info organisation="com.myspotontheweb" module="ivy_packager"/>
    <dependencies>
        <dependency org="ch.oscg" name="jreleaseinfo" rev="1.3.0"/>
    </dependencies>
</ivy-module>

Declare two resolvers. Default is Maven2, the other is a packager configured to look locally for instructions. (See also the Ivy Roundup project)

ivysettings.xml

<ivysettings>
    <settings defaultResolver="maven2"/>
    <resolvers>
        <ibiblio name="maven2" m2compatible="true"/>

        <packager name="repackage" buildRoot="${user.home}/.ivy2/packager/build" resourceCache="${user.home}/.ivy2/packager/cache">
            <ivy pattern="file:///${basedir}/repository/[organisation]/[module]/[revision]/ivy.xml"/>
            <artifact pattern="file:///${basedir}/repository/[organisation]/[module]/[revision]/packager.xml"/>
        </packager>
    </resolvers>
    <modules>
        <module organisation="ch.oscg" name="jreleaseinfo" resolver="repackage"/>
    </modules>
</ivysettings>

The magic is containing in the "packager" file. At resolve time this will be used to generate an ANT script that both downloads and extracts the required jars. (No need to put this logic into your build.xml)

repository/ch.oscg/jreleaseinfo/1.3.0/packager.xml

<packager-module version="1.0">

    <property name="name" value="${ivy.packager.module}"/>
    <property name="version" value="${ivy.packager.revision}"/>
    <property name="zipname" value="${name}-${version}"/>

    <resource dest="archive" url="http://sourceforge.net/projects/jreleaseinfo/files/jreleaseinfo/jreleaseinfo%201.3.0/jreleaseinfo-1.3.0.zip/download" sha1="9386d92758e627d04c2480b820731fd538b13a3f" type="zip"/>

    <build>

        <move file="archive/${zipname}/${zipname}.jar" tofile="artifacts/jars/${name}.jar"/>

    </build>
</packager-module>

To reduce the number of files I omitted the module's ivy.xml. This appears to be optional unless you want to declare it's licence and other attributes that should be present in a public repository.

Mark O'Connor