6

I have the following ivy file:

<configurations defaultconfmapping="buildtime">
    <conf name="buildtime" visibility="private" description="Libraries needed only for compilation" />
    <conf name="runtime" description="Libraries only needed at runtime" />
    <conf name="test" description="Libraries only needed for testing" />
</configurations>

<dependencies>
  <dependency org="net.java.dev" name="jvyaml" rev="0.2.1" conf="runtime" />
  <dependency org="org.apache.solr" name="solr-core" rev="3.6.0" conf="runtime" />

</dependencies>

and I have an ant retrieve task that looks like this:

<target name="retrieve-all" depends="resolve">
    <ivy:retrieve pattern="lib/[conf]/[artifact]-[revision].[ext]" conf="*" />
</target>

The weird thing is, that all the solr dependencies download into lib/runtime as I'd expect, but the jvyaml module does not! It 'resolves', but will not download into the lib/runtime directory unless I change the dependency declaration to:

<dependency org="net.java.dev" name="jvyaml" rev="0.2.1" conf="runtime->master" />

What is this master configuration and why is it needed to pull the jvyaml jar, but not solr?

Thanks

2 Answers 2

21

I would suggest restructuring your configurations as follows:

<ivy-module version="2.0">
    <info organisation="com.myspotontheweb" module="demo"/>

    <configurations>
        <conf name="compile" description="Libraries needed only for compilation" />
        <conf name="runtime" description="Libraries only needed at runtime" extends="compile" />
        <conf name="test" description="Libraries only needed for testing" extends="runtime" />
    </configurations>

    <dependencies>
        <dependency org="net.java.dev" name="jvyaml" rev="0.2.1" conf="runtime->default" />
        <dependency org="org.apache.solr" name="solr-core" rev="3.6.0" conf="runtime->default" />
    </dependencies>

</ivy-module>

Important changes introduced:

  1. Use the more standard "compile" configuration
  2. Configuration inheritance using the "extends" attribute. Compile dependencies can then be automatically included in both the runtime and test configurations.
  3. Use configuration mappings, for example: conf="runtime->default". This makes it obvious which local configuration is associated with which remote configuration.

Configuration mappings explained

Configurations are a powerful ivy feature. When ivy downloads Maven modules it performs an internal translation and assigns a standard set of configurations, listed in this answer:

When declaring a dependency it's a good idea to always make use of a configuration mapping, so that there is no doubt where the dependencies artifacts are assigned.

For example:

<dependency org="??" name="??" rev="??" conf="runtime->default" />

Here we're saying we want the remote module's default dependencies associated with our local runtime configuration.

In practice, there are only two remote configuration mappings you'll actually need:

  • default: The remote module's artifact and all it's runtime transitive dependencies
  • master: The remote module's artifact only (No transitive dependencies)

In conclusion, I think your problem was caused by the fact that the remote Maven module's "runtime" scope does not include Maven module's artifact, instead you were getting the non-existant transitive dependencies of the module jvyaml :-(

Some additional advice

I'd also suggest generating an ivy dependency management report, as follows:

<target name="init" description="Resolve dependencies and populate lib dir">
    <ivy:resolve/>
    <ivy:report todir="${build.dir}/ivy-report" graph="false"/>
    <ivy:retrieve pattern="lib/[conf]/[artifact]-[revision].[ext]"/>
</target>

The report will help explain how each dependency ends up on different configurations. Also really useful for determining how transitive dependencies are being managed.

And finally, here's where the configuration inheritance pays off, creating ivy managed ANT classpaths:

<target name="init" description="Resolve dependencies and set classpaths">
    <ivy:resolve/>
    <ivy:report todir="${build.dir}/ivy-report" graph="false"/>

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

Notice that the original solr-core is not retrieved either. After your resolve, go the cache and check the ivy.xml files for both modules.

You will see that they publish their artifacts in conf=master only

<artifact name="jvyaml" type="jar" ext="jar" conf="master"/>

<artifact name="solr-core" type="jar" ext="jar" conf="master"/>

Which means, you have to do explicit configuration mapping to denote that your builtime configuration should evoke the 'master' configuration of your dependencies. (check configuration mapping).

HOWEVER, the dependencies of the solr-core, have the configuration mapping as you could see in the ivy.xml file:

<dependency org="org.apache.solr" name="solr-solrj" rev="3.6.0" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>

I think it's the master(*) thingy.

What I usually do is in my own ivy.xml file when I declare dependencies I do the mapping:

  <dependency org="net.java.dev" name="jvyaml" rev="0.2.1" conf="runtime->master" />

This one says the runtime be evoking the master configuration in the designated dependency.

You could do

conf="runtime,test->master"

as well

Not the answer you're looking for? Browse other questions tagged or ask your own question.