views:

62

answers:

3

I'm trying to set up my ant build so that the targets which run Ivy functions are completely separated from the ones that the continuous build and most developers run. I want one target to download updated dependencies, which I'll check in. Other targets will set up their classpath by including *.jar from the relevant directory.

I have two configurations:

<configurations>
    <conf name="compile" />
    <conf name="test" />
</configurations>

I have some dependencies:

<dependency
    org="my.org"
    name="some-lib"
    rev="latest.release"
    conf="compile->default" />
<dependency
    org="my.org"
    name="some-test-lib"
    rev="latest.release"
    conf="test->default" />

And I download those dependencies and their transitive dependencies using ivy:retrieve:

<ivy:retrieve
    pattern="lib/[conf]/[type]/[artifact]-[revision].[ext]"
    sync="true"
    file="ivy.xml" />

The problem is that I'm seeing some duplicates jars between the compile and the test directories, which come from transitive dependencies. Since I want to check in all these jars and use them for creating classpaths, I'd like to avoid duplicates. Is this possible?

lib/compile/jar/some-lib-1.0.jar
lib/compile/jar/slf4j-api-1.5.11.jar
lib/test/jar/some-test-lib-1.0.jar
lib/test/jar/junit-4.7.jar
lib/test/jar/slf4j-api-1.5.11.jar

+1  A: 

This is not duplication, each configuration is a separate set of jars and the ivy restrieve task is faithly creating each set....

Perhaps it would make more sense to create the classpaths directly, rather than populating a local lib directory.

Here's a snippet of my ANT build files:

<target name="get-dependencies">
    <ivy:resolve/>

    <ivy:cachepath pathid="compile.path" conf="compile" />
    <ivy:cachepath pathid="test.path" conf="test" />
</target>

<target name="compile" depends="get-dependencies">
    <javac srcdir="src" destdir="build/classes" classpathref="compile.path"/>
</target>

I normally only use the ivy retrieve task when I need to create a local copy of a set of jars, for example assembling a web app's directory:

<ivy:retrieve pattern="build/WEB_INF/lib/[artifact].[ext]" conf="runtime"/>

Update

Another alternative is to instruct ivy to exclude the slf4j module when downloading transient dependencies, as follows:

<dependency org="my.org" name="some-lib" rev="latest.release" conf="compile->default">
    <exclude module="slf4j-api"/> 
</dependency>

<dependency org="my.org" name="some-test-lib" rev="latest.release" conf="test->default">
    <exclude module="slf4j-api"/> 
</dependency>
Mark O'Connor
I want to check in the lib directory though so that I can create classpaths from *.jar in certain directories. That way the build doesn't depend on the network at all.
Craig P. Motlin
The **cachepath** task creates a classpath based on the jars located in the local ivy cache so there's no network involved. The **retrieve** task works the same way copying files from your cache into the specified directory
Mark O'Connor
If you're using the directories to create classpaths, why are you deleting jars? If the jar should not be in the classpath it can excluded within the dependency declaration. See http://ant.apache.org/ivy/history/latest-milestone/ivyfile/exclude.html
Mark O'Connor
@Mark No one else on the project will use Ivy, so they will not have an Ivy cache. Their classpaths will be created by including all the jars in the directories that Ivy creates that I will check in. I could check in duplicates but it's wasteful to have all that in VCS.
Craig P. Motlin
A: 

If I can do this through Ivy directly, that would be best. For now I've solved the problem by just deleting duplicates using ant.

Craig P. Motlin
A: 

Try the following. Your test should extend compile

<dependency
org="my.org"
name="some-test-lib"
rev="latest.release"
conf="**test->compile**" />

If i am right IVY should find that test extends compile and would download slf4j only once.

Tried it, didn't work.
Craig P. Motlin