How to take two revisions of the same jar? - ivy

I have two versions of the same jar (3.2 and 2.2.1) I need to use both of them but ivy evicts older revision. How to configure ivy to take two versions?
<dependency org="asm" name="asm-all" rev="3.2">
<artifact name="asm-all" type="jar"/>
</dependency>
<dependency org="asm" name="asm-all" rev="2.2.1">
<artifact name="asm-all" type="jar"/>
</dependency>

You need to use ivy configurations. This is a very flexible mechanism to manage arbitrary groups of dependencies.
The example below places each version of the jar onto a separate configuration. This can be used later to create two classpaths, using the ivy cachepath task.
Example
ivy.xml
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo"/>
<configurations>
<conf name="compile1" description="Required to compile application1"/>
<conf name="compile2" description="Required to compile application2"/>
</configurations>
<dependencies>
<!-- compile1 dependencies -->
<dependency org="asm" name="asm-all" rev="3.2" conf="compile1->master"/>
<!-- compile2 dependencies -->
<dependency org="asm" name="asm-all" rev="2.2.3" conf="compile2->master"/>
</dependencies>
</ivy-module>
Notes:
Version 2.2.1 does not exist in Maven Central
Note the configuration mapping "??? -> master". In Maven the remote master configuration mapping resolves to the main module artifact without dependencies. (See)
build.xml
<project name="demo" default="init" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="init" description="Use ivy to resolve classpaths">
<ivy:resolve/>
<ivy:report todir='build/ivy' graph='false' xml='false'/>
<ivy:cachepath pathid="compile1.path" conf="compile1"/>
<ivy:cachepath pathid="compile2.path" conf="compile2"/>
</target>
<target name="clean" description="Clean built artifacts">
<delete dir="build"/>
</target>
<target name="clean-all" depends="clean" description="Additionally purge ivy cache">
<ivy:cleancache/>
</target>
</project>
Notes:
Always a good idea to generate an ivy report. It will tell you which dependencies exist on which ivy configuration.
This example shows ivy managing ANT paths. You can also use ivy configurations with the ivy retrieve task to populate a local "lib" directory when assembling something like a webapp WAR file.

Related

apache ant ivy conditionally build a module

I have a usecase where in I had to create a new module in out project. Our main project has multiple modules and each module is a java project. We are using ivy for dependency resolution. Now the probkem is that in the new module , I had to use java 1.7 API (WatchService) which is not there in java 1.6. Now in build.xml I can check for the java version and accordingly build this new module depending on the java -version. The problem comes in ivy.xml of or main web project where I have to mention the jar file of the new module as a dependency to include in the generated war file. If the java version is 1.7 , then in that case problem wont be there as the jar will be build and the its dependency will be resolved. the problem arises when the java version is 1.6. The jar file wont be created and when its time to generate the war file, ivy wont be able to resolve the dependency as the jar file is not there. Maybe the approach that I am trying to apply here is not fine. Please advice me on how to work around this particular use case.
rampal
In ivy you can use configurations to maintain different sets of depenedencies:
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo"/>
<configurations>
<conf name="compile_jdk7" description="Java JDK7 compile dependencies"/>
<conf name="compile_jdk6" description="Java JDK6 compile dependencies"/>
</configurations>
<dependencies>
<!-- JDK7 dependencies -->
<dependency org="org.myorg" name="module1" rev="latest.integration" conf="compile_jdk7->default"/>
<dependency org="org.myorg" name="module2" rev="latest.integration" conf="compile_jdk7->default"/>
<dependency org="org.myorg" name="module3" rev="latest.integration" conf="compile_jdk7->default"/>
<!-- JDK6 dependencies -->
<dependency org="org.myorg" name="module1" rev="latest.integration" conf="compile_jdk6->default"/>
<dependency org="org.myorg" name="module3" rev="latest.integration" conf="compile_jdk6->default"/>
</dependencies>
</ivy-module>
and in the build file use a condition task to choose which configuration is used at run-time to populate the classpath, using the cachepath task:
<project name="demo" default="compile" xmlns:ivy="antlib:org.apache.ivy.ant">
<condition property="compile.config" value="compile_jdk7">
<equals arg1="${ant.java.version}" arg2="1.7"/>
</condition>
<condition property="compile.config" value="compile_jdk6">
<equals arg1="${ant.java.version}" arg2="1.6"/>
</condition>
<target name="resolve" description="Use ivy to resolve classpaths">
<ivy:cachepath pathid="compile.path" conf="${compile.config}"/>
</target>
<target name="compile" depends="resolve" description="Compile code">
<javac ...... classpathref="compile.path"/>
</target>
</project>

Ivy Retrieve with Classifiers

I have the following ivy.xml:
<ivy-module version="1.0"
xmlns:maven="http://maven.apache.org">
<configurations>
...
</configurations>
<dependencies>
<dependency org="com.foo" name="fubur"
rev="1.3" conf="runtime->default"/>
<dependency org="com.snafu" name="barfu"
rev="1.4" conf="runtime->default">
<artifact name="barfu"
maven:classifier="ID_10T"
type="jar" ext="jar"/>
</dependency>
</dependencies>
</ivy-module>
In my build.xml, I want to retrieve all of my jars for the war I'm building:
<ivy:retrieve
pattern="${lib.dir}/[artifact]-[classifier]-[revision].[ext]"
conf="runtime"/>
No, that won't work... There's no classifier in fubar-1.3.jar. It will download as fubar--1.3.jar
<ivy:retrieve
pattern="${lib.dir}/[artifact]-[revision].[ext]"
conf="runtime"/>
That's no good either. barfu-ID_10T-1.4.jar will download as barfu-1.4.jar.
I would like the jars in my war to be included as barfu-ID_10T-1.4.jar and fubar-1.3-jar`. Is there an easy way of doing that? I know I could create two different configurations, but that is overkill. I'd rather just have the jars miss-named since it really doesn't affect the war itself.
Use parentheses to specify optional components of an attribute pattern:
<ivy:retrieve
pattern="${lib.dir}/[artifact](-[classifier])-[revision].[ext]"
conf="runtime"/>

Ivy/Maven Resolve: Don't pull transitive "provided" jars

I'm using Ivy for my projects, but we're using Artifactory as our jar repository. I actually use <ivy:makepom> Ant task to create a Maven pom.xml, so I can deploy the jars and wars back to my Maven repository via the Maven deploy:deploy workflow.
I build a big jar called common-all.jar that requires about 30 jars for its compilation. I specify about 10 jars, and Ivy pulls down the dependencies. As part of the compile process, I specify the log4j jar, and some JBoss jars. These jars, of course, will be provided by our environment.
With this Jar, I also a bunch of wars. I specify the common-all.jar as part of my dependency, and the 30 jars that common-all.jar requires are also pulled down. All is well and good.
The problem is when I build the war. I do not want the JBoss jars or the log4j jars included as part of the war. These will be provided by the environment. I've marked them as provided in the pom.xml file. when I build common-all.jar.
Now, the question is how do I specify that I want these when I compile the code for the war, but I don't want to include them in my war itself.
Here's a sample of my ivy.xml file.
How can I specify that the common-all.jar requires certain specific jars for compilation, but when I build it in a war, I don't want all of these jars
<ivy-module version="1.0">
<info
organisation="com.travelclick"
module="TC-AppUtil"
revision="4.1"
status="release"/>
<configurations>
<conf name="default" visibility="public"
description="The single built artifact. Nothing else"/>
<conf name="compile" visibility="public"
description="The master module and transitive dependencies"/>
<conf name="provided" visibility="public"
description="Needed for compile. Will be provided outside or war"/>
<conf name="runtime" visibility="public"
description="Not required for compile, but for runtime"
extends="compile"/>
<conf name="default" visibility="public"
description="The default configuration"
extends="runtime"/>
<conf name="test" visibility="private"
description="Required for testing" extends="runtime"/>
</configurations>
<dependencies>
<!-- Normal Compile Dependencies -->
<dependency org="ximpleware" name="vtd-xml"
rev="2.5" conf="compile->default"/>
<dependency org="com.travelclick" name="common-all"
rev="4.1" conf="compile->compile,runtime"/>
<!-- Testing -->
<dependency org="junit" name="junit"
rev="4.10" conf="test->default"/>
</dependencies>
</ivy-module>
You haven't demonstrated how you declare the common-all dependency, so I'll make up the following example:
<dependency org="mygroup" name="common-all" rev="1.0" conf="compile->default;provided"/>
The magic is the configuration mapping:
The local "compile" configuration is mapped to the common module and its default (compile) scope dependencies, and
The local "provided" configuration is mapped to the common module and its provided scope dependencies.
Inside your build file the configurations are used as follows:
<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve">
<ivy:resolve/>
<ivy:cachepath pathid="compile.path" conf="compile"/>
<ivy:cachepath pathid="provided.path" conf="provided"/>
</target>
<target name="compile" depends="resolve">
<javac ...
<classpath>
<path refid="compile.path"/>
<path refid="provide.path"/>
</classpath>
</javac>
</target>
<target name="build" depends="compile">
<ivy:retrieve pattern="build/lib/[artifact].[ext]" conf="runtime"/>
<war ...
<lib dir="build/lib"/>
</war>
</target>
<target name="clean">
<delete dir="build"/>
<ivy:cleancache/>
</target>
</project>

Keep Ivy from including test dependencies

Consider an ivy.xml like the following:
<ivy-module version="2.0">
<info organisation="com.foo" module="FooBar" />
<dependencies>
<dependency org="net.sf.ehcache" name="ehcache-core" rev="2.2.0" />
<!--...-->
</dependencies>
</info>
</ivy-module>
When I run Ivy, it fetches all dependencies for EHCache, even testing dependencies. Specifically, it tries to pull in Hibernate 3.5.1 (which, in the POM file, is listed as a "test" dependency).
How do I prevent Ivy from including test dependencies? I could list it as an excluded dependency, but I don't want to have to do this for every test dependency. I'm new to Ivy and used to the way Maven does things. I was reading about configurations but I don't understand how this aspect of Maven's "scope" maps to "configurations."
You need to define the configuration of the dependency like:
<dependency org="net.sf.ehcache" name="ehcache-core" rev="2.2.0" conf="compile"/>
If you omit conf it is assumed, that you meant conf ="*", which will download all configurations for that dependency.
Here is a simple Example:
<configurations>
<conf name="test" visibility="public" />
<conf name="compile" visibility="public" />
</configurations>
<publications>
<artifact name="${project.name}" type="jar" conf="compile" ext="jar"/>
<artifact name="${project.name}-test" type="jar" conf="test" ext="jar"/>
</publications>
<dependencies>
<!-- COMPILE -->
<dependency org="log4j" name="log4j" rev="1.2.14" conf="compile->*"/>
<dependency org="apache" name="commons-net" rev="2.0" conf="compile->*"/>
<dependency org="itext" name="itext" rev="1.4.6" conf="compile->*"/>
<dependency org="jsch" name="jsch" rev="0.1.29" conf="test->*"/>
<!-- TEST -->
</dependencies>
In this example jsch will be included in the test and the compile configuration.
If you resolve this dependency later with conf ="compile" you will get all dependencies EXCEPT jsch.
If you resolve this dependency with conf ="test" you will get jsch only.
And if test would extend compile, you would get all jars.
<configurations>
<conf name="test" visibility="public" extends="compile" />
<conf name="compile" visibility="public" />
</configurations>

Split retrieved artifacts in two separate lib directories

In my web application, there are two separate lib directories:
/lib, and
/web/webroot/WEB-INF/lib.
The idea behind it is that libraries in the latter one are used by front-end code only, and the first one by both the front-end and the business logic code. There is a class loader in place which lets the business logic code not see the jars in /web/webroot/WEB-INF/lib.
How can I tell ivy that certain dependencies should go to the second directory while all others go to first one?
It's not trival since the the web class loader can see jars in both directories and I don't want jars to be in both directories.
Configurations are used to create logical groupings of dependencies:
ivy.xml
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo"/>
<configurations>
<conf name="frontEnd" description="Jars used by front end"/>
<conf name="businessLogic" description="Jars used for business logic"/>
</configurations>
<dependencies>
<dependency org="commons-lang" name="commons-lang" rev="2.5" conf="businessLogic->default"/>
<dependency org="commons-codec" name="commons-codec" rev="1.4" conf="businessLogic->default"/>
<dependency org="commons-cli" name="commons-cli" rev="1.2" conf="frontEnd->default"/>
<dependency org="commons-logging" name="commons-logging" rev="1.1.1" conf="frontEnd->default"/>
</dependencies>
</ivy-module>
The ivy retrieve ant task can use these configurations to populate your directories:
build.xml
<target name="init" description="--> retrieve dependencies with ivy">
<ivy:retrieve conf="businessLogic" pattern="lib/[artifact].[ext]"/>
<ivy:retrieve conf="frontEnd" pattern="web/webroot/WEB-INF/lib/[artifact].[ext]"/>
</target>
Example
$ find . -type f
./build.xml
./ivy.xml
./lib/commons-lang.jar
./lib/commons-codec.jar
./web/webroot/WEB-INF/lib/commons-cli.jar
./web/webroot/WEB-INF/lib/commons-logging.jar