How to configure Ivy for Ant build
Asked Answered
P

2

18

I currently have ANT_HOME located at /home/<myuser>/ant/1.8.4/ant-1.8.4.

I just downloaded the Apache Ivy tarball that includes its dependencies. I extracted it to /home/<myuser>/ivy/2.3.0-rc1/ivy-2.3.0-rc1.

I then copied /home/<myuser>/ivy/2.3.0-rc1/ivy-2.3.0-rc1/lib/*.jar to ANT_HOME/lib. If my understanding of how Ant works with plugins/extensions is correct, then Ant should now be able to access all of Ivy's tasks at runtime.

My next question is, how do I define Ivy tasks inside my Ant buildfile? Say I want to use ivy-retrieve, ivy-resolve and ivy-publish tasks. What are all the configurations I need to do (in the XML) to get these tasks working when I run my Ant build from the command-line (I will not be building through the Ant-Eclipse plugin). Thanks in advance!

Prosthesis answered 11/9, 2012 at 22:33 Comment(0)
A
65

First, you have to define a <taskdef> to point to the Ivy tasks.

<property environment="env"/>
<property name="ivy.home" value="${env_IVY_HOME}"/>

<taskdef resource="org/apache/ivy/ant/antlib.xml">
    <classpath>
        <fileset dir="${ivy.home}">
            <include name="*.jar"/>
        </fileset>
    </classpath>
</taskdef>

That will give you access to the Ivy tasks. You'd use these tasks like this:

<cachepath pathid="main.classpath" conf="compile"/>

The problem is that your Ivy tasks names might clash with other Ant tasks. For example, there's an Ivy task <report>. To solve this, you can create an Ivy namespace. To do that, you put a reference in your namespace in the <project> entity like this:

<project name="my.proj" default="package" basedir="."
    xmlns:ivy="antlib:org.apache.ivy.ant"/>

Now, when you define the Ivy tasks, you can use that antlib:org.apache.ivy.ant reference to your ivy namespace. Same taskdef as before, but with a uri field:

<property environment="env"/>
<property name="ivy.home" value="${env_IVY_HOME}"/>

<taskdef resource="org/apache/ivy/ant/antlib.xml"
    uri="antlib:org.apache.ivy.ant">
    <classpath>
        <fileset dir="${ivy.home}">
            <include name="*.jar"/>
        </fileset>
    </classpath>
</taskdef>

By the way, there's nothing special about that uri. I could have done this:

<project name="my.proj" default="package" basename="."
   xmlns:ivy="pastrami:with.mustard">

[...]
<taskdef resource="org/apache/ivy/ant/antlib.xml"
    uri="pastrami:with.mustard">
    <classpath>
        <fileset dir="${ivy.home}">
            <include name="*.jar"/>
        </fileset>
    </classpath>
</taskdef>

The point is now you can prefix your task names with ivy:. Instead of this:

<cachepath pathid="main.classpath" conf="compile"/>

You can now do this:

<ivy:cachepath pathid="main.classpath" conf="compile"/>

And that's how you gain access to your Ivy Ant tasks.

Now, you have access to your Ivy Ant tasks, you need to define an ivysettings.xml file and use the <ivy:settings/> task to point there:

 <ivy:settings file="${ivy.home}/ivysettings.xml"/>

There is a default ivysettings.xml file embedded in Ivy that will point you to the world wide Maven repository system. If you don't have a company wide Maven repository, then you can use the default ivysettings.xml file:

<ivy:settings/>

That's pretty simple.

Once you've done that, you need to read in and resolve your ivy.xml file which usually sits in the root of your project in the same directory as your build.xml file.

Basically, your ivy.xml file contains references to the third party jars you want to bring into your project. For example:

<dependencies>
    <dependency org="log4j"  name="log4j" rev="1.2.17" conf="compile->default"/>
    <dependency org="junit"  name="junit" rev="4.10" conf="test->default"/>
</dependencies>

What this is saying is that I need the log4j.jar (revision 1.2.17) for compilation (and for compiling tests too) and I need junit.jar (revision.4.10) for compilation of my test code.

The compile->default is a mapping of my compile configuration to Maven's default configuration (which says I just want the Jar and any other jars that it might depend upon.

Where's does my compile configuration come from? I define it in my ivy.xml. There are ten standard configurations. This also goes into your ivy.xml file:

<configurations>
  <conf name="default" visibility="public" description="runtime dependencies and master artifact can be used with this conf" extends="runtime,master"/>
  <conf name="master" visibility="public" description="contains only the artifact published by this module itself, with no transitive dependencies"/>
  <conf name="compile" visibility="public" description="this is the default scope, used if none is specified. Compile dependencies are available in all classpaths."/>
  <conf name="provided" visibility="public" description="this is much like compile, but indicates you expect the JDK or a container to provide it. It is only available on the compilation classpath, and is not transitive."/>
  <conf name="runtime" visibility="public" description="this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath." extends="compile"/>
  <conf name="test" visibility="private" description="this scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases." extends="runtime"/>
  <conf name="system" visibility="public" description="this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository."/>
  <conf name="sources" visibility="public" description="this configuration contains the source artifact of this module, if any."/>
  <conf name="javadoc" visibility="public" description="this configuration contains the javadoc artifact of this module, if any."/>
   <conf name="optional" visibility="public" description="contains all optional dependencies"/>
 </configurations>

You can use any configuration name you want, but these map to the default Maven configurations and are widely used.

Once you have your ivy.xml file defined, you can use <ivy.resolve> to resolve your dependencies:

<ivy:resolve/>

So, we have the following:

  1. How to use <taskdef> in your build.xml to incorporate the Ivy Ant tasks into your build.
  2. How to use the Ivy Ant task <ivy:settings> to configure Ivy.
  3. How to use <ivy:resolve/> to read in your ivy.xml file and resolve your third party jar dependencies.

Now, you probably want to actually use those jar files. There are three ways to do this:

 <ivy:cachepath pathid="main.classpath" conf="compile"/>

The <ivy:cachepath/> task will create a classpath (in this case called main.classpath) that points to the jars you have in your ivy.xml file's compile configuration. This is used most of the time.

If you need a fileset, you can use this:

 <ivy:cachefileset setid="compile.fileset" conf="compile"/>

In this case, it will create a fileset with a refid of compile.fileset.

Sometimes you have to bring the jars into your project. For example, if you create a war or ear file, you want to enclose your jars. In that case, you can use this:

<property name="lib.dir" value="${target.dir}/lib"/>
<ivy:retrieve pattern="${lib.dir}/[artifact].[ext]"
     conf="runtime"/>

That will fetch your jars into the ${lib.dir} directory, so you can include them in wars or ears.

Sorry for the long answer, but there are a lot of steps to cover. I highly recommend Manning's book Ant in Action which has a whole chapter on Ivy.

Arguable answered 12/9, 2012 at 3:6 Comment(4)
This is by far the most comprehensive answer to any Ivy-related question I've asked or have come across, I wish I could upvote it more. Thank you for taking the time to help me here, it was perfect. One quick followup question (if I may): I do plan on having my own hosted repository, probably managed by Artifactory. Anytime I've worked with Ivy, I've seen my co-workers define their conf attributes as conf="*->*" or conf=compile->default, but nobody seems to have a clear understanding of what these do, and why...Prosthesis
You mention that its a mapping between the local Ivy config (ivy.xml) and the repository its resolving against, and you were even generous enough to show what a compile config might look like (vs. a test config). But what about on the repository-side (the right-hand side of the "arrow" operator)? What does "*->*" map to? What about "default"? Just curious because no matter how many times I read the Ivy docs, I can't seem to wrap my head around it. Thanks again for all your help!Prosthesis
There is no standard configs in Ivy. You have to define your configs in your ivy.xml file. The standard ones mentioned in my post map to the Maven scopes. I can define a single config in my ivy.xml, or I can add ones I didn't mention above. For example, some people have added a generated-sources configuration in ivy.xml for things like axis2 and WSDL files. The thing is you have to map your config to the repos' config. I've never tried *->*. I guess it maps all of your configurations in your ivy.xml` to all the repository configurations. I'll have to give it a try.Arguable
At 2015, this is still the most comprehensive and clear tutorial on ivy ant tasksVardon
K
15

David gave a very fine answer, but I'd like to point out that the taskdef is not required. Provided the ivy.jar is in the expected location the namespace declaration at the top of the ANT file is enough:

<project ..... xmlns:ivy="antlib:org.apache.ivy.ant">

For more detail I'd recommend reading about how ANT libs work.

The following answer provides some more "setting up ivy" advice:

Kuomintang answered 12/9, 2012 at 21:30 Comment(1)
this is the correct and simple answer, if ivy.jar is in ant_home/libMislay

© 2022 - 2024 — McMap. All rights reserved.