Apache Ivy Install Task and Local Repositories


April 4, 2014 Maithilish

Chapter 6. Apache Ivy Install Task

To build private repository like local or shared repositories we have to copy the module’s files and artifacts from public repository to private repository and we have to use Apache Ivy Install task for this. It resolves a module and its dependencies from a repository and install them in another repository. Apache Ivy Install task copies module’s ivy file and artifacts from a source repository to a target repository.
Let’s see Apache Ivy Install task in action by building some private repositories.

6.1. Ivy Local Repository

Apache Ivy Local Repository

Local repository is a private repository where access is restricted to the owner. By default, the local repository is ${ivy.default.ivy.user.dir}/local. Built-in variable ${ivy.default.ivy.user.dir} points to $HOME/.ivy2 and hence local repository resides in $HOME/.ivy2/local folder.

Add following file build file to work dir.
build.xml

<project name="localrepository" default="install" xmlns:ivy="antlib:org.apache.ivy.ant">
 <target name="install" description="--> install modules to localreporsitory">
  <ivy:install organisation="commons-lang" module="commons-lang" 
   revision="2.6" transitive="true" overwrite="false" 
   from="public" to="local" />
 </target>
</project>

This <ivy:install> definition installs commons-lang 2.6 from public repository to local file system repository. Run Ant and Ivy Install task creates a new local directory in $HOME/.ivy2. Repository layout is shown in the next figure.

Apache Ivy Local Repository

Figure 6.1. Local Repository layout


We have not provided any info about local, public resolver and pattern to Ivy, to install the files and artifacts in the local repository. From where Ivy gets details about the repository. We get a clue from the following lines of the build output.
[ivy:resolve] :: loading settings :: url = jar:file:/opt/ant/apache-ant-1.8.2/lib/ivy-.2.0.jar!
/org/apache/ivy/core/settings/ivysettings.xml
So, Apache Ivy uses a default setting file – ivysettings.xml packaged in ivy-2.0.jar. To know what’s there in this file, extract ivy-2.0.jar archive some temporary location, and you will find ivysettings.xml in org/apache/ivy/core/settings. Contents of this file is are follows.
/org/apache/ivy/core/settings/ivysettings.xml

<ivysettings>
 <settings defaultResolver="default" />
 <include url="${ivy.default.settings.dir}/ivysettings-public.xml" />
 <include url="${ivy.default.settings.dir}/ivysettings-shared.xml" />
 <include url="${ivy.default.settings.dir}/ivysettings-local.xml" />
 <include url="${ivy.default.settings.dir}/ivysettings-main-chain.xml" />
 <include url="${ivy.default.settings.dir}/ivysettings-default-chain.xml" />
</ivysettings>

By default, Apache Ivy comes with shared, default, local, public, main resolvers. Definition of each of this resolvers is contained in separate settings file. In org/apache/ivy/core/settings folder you find these five settings files. Let’s go through the contents of ivysettings-public.xml and ivysettings-local.xml.
/org/apache/ivy/core/settings/ivysettings-public.xml

<ivysettings>
 <resolvers>
  <ibiblio name="public" m2compatible="true" />
 </resolvers>
</ivysettings>

For public repository, Ivy uses built-in resolver <ibiblio> which points to http://www.ibiblio.org/maven/ repository.
/org/apache/ivy/core/settings/ivysettings-local.xml

<ivysettings>
 <property name="ivy.local.default.root" 
              value="${ivy.default.ivy.user.dir}/local" 
              override="false" />
 <property name="ivy.local.default.ivy.pattern" 
              value="[organisation]/[module]/[revision]/[type]s/[artifact].[ext]" 
              override="false" />
 <property name="ivy.local.default.artifact.pattern" 
              value="[organisation]/[module]/[revision]/[type]s/[artifact].[ext]" 
              override="false" />
 <resolvers>
  <filesystem name="local">
   <ivy pattern="${ivy.local.default.root}/${ivy.local.default.ivy.pattern}" />
   <artifact pattern="${ivy.local.default.root}/$ivy.local.default.artifact.pattern}" />
  </filesystem>
 </resolvers>
</ivysettings>

For local repository Ivy pattern and Artifact pattern [organisation]/[module]/[revision]/[type]s/[artifact].[ext] defines the layout of Local repository.
Once, local repository is successfully created, it is always a good idea to do a quick resolve to ensure that Ivy is able to retrieve artifacts from our new repository without any naming conflicts. To do that, add ivy.xml to work directory
ivy.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
 <info organisation="in.ex" module="simpleivy" status="integration">
 </info>
 <dependencies>
  <dependency org="commons-lang" name="commons-lang" rev="2.6" />
 </dependencies>
</ivy-module>

This is the same old ivy.xml file which we used earlier for resolve task. Add following snippet to build.xml and run ant.
buil.xml

....

<target name="resolve" description="resolve dependencies with ivy">
             <ivy:retrieve />
</target>

....

Ivy should do a resolve and retrieve and place the retrieved artifacts in the lib directory without any protest.

Apache Ivy Local Repository retrieval to lib

Figure 6.2. Retrieval from Local Repository


Prime Ivy cache from Local Repository

Our local repository is now good to go. But observe the output.

[ivy:resolve] confs: [default]
[ivy:resolve] found commons-lang#commons-lang;2.6 in public
[ivy:resolve] :: resolution report :: resolve 172ms :: artifacts dl 25ms
It indicates that commons-lang is found in public. By default, Ivy first searches in the local, then shared and then public. But it is still resolving from public repository, even though the module is in local. Reason is cache. During install, it has copied the module from public to cache and then to local and that copy is still exists in cache. On subsequent resolves, it finds the artifacts resolved from public repository in cache and says that it has found it in public.

Warning

In the next step, we are going to clear the cache which simply deletes the $HOME/.ivy2/cache directory. If your cache contains a large number of modules then you will lose them. Just to explain the resolve mechanism, we are going to clean the cache. So, try this when you have a small cache.
Use <ivy:cleancache> task to clear the cache. Add following snippet to build.xml and run ant clean-cache
build.xml

....

<target name="clean-cache" description="--> clean the cache">
<ivy:cleancache />
</target>

....

<ivy:cleancache> task deletes the $HOME/.ivy2/cache directory and that clears the cache. Next, run <ivy:resolve> task and resolve happens from the local repository. Output indicates that commons-lang is found in local and triggers a download to the cache.

Local Resolve

It is important to note that in case of local resolve too Ivy first searches the cache for artifacts and if it is not found, then, it copies the artifacts from the local repository to cache and then say the module is resolved and downloaded.
Sequence of download or copy during a resolve from any type of the repository is as follows:
Public -> cache -> project build path
Local -> cache -> project build path

 

Ivy Local Repository – Overriding the default settings

There are two ways to override the default settings, either through setting the properties in Ant target or through ivysettings.xml file.

As an exercise, let’s change the layout of the local repository. Modify the build.xml.
build.xml

<project name="shared repository" default="install" 
 xmlns:ivy="antlib:org.apache.ivy.ant">
 <target name="install" description="local at non default location">
  <property name="ivy.local.default.ivy.pattern" 
         value="[organisation]/[module]/ivys/ivy-[revision].xml" />
  <property name="ivy.local.default.artifact.pattern" 
         value="[organisation]/[module]/[type]s/[artifact]-[revision].[ext]" />
  <ivy:install organisation="commons-lang" module="commons-lang" revision="2.6" 
            transitive="true" overwrite="false" from="public" to="local" />
 </target>
</project>

We have used Ant property to change ivy pattern and artifact pattern. Install still uses default local resolver, but layout of repository is changed to the new pattern.

Delete Local Repository

Before running this example, you may have to clear the local repository as commons-lang module is already installed on local. Deleting the local repository is easy, just delete the directory $HOME/.ivy2/local.
Run Ant and see whether the local repository layout is changed as indented.
Alternatively, we may use ivysettings.xml to override the default settings. Following ivysettings.xml defines a chain resolver named myresolver which points to $HOME/.ivy2/local but layout pattern is different from the default local resolver. Place ivysettings.xml file along with build.xml and Ivy loads it instead of default file that comes with Ivy.
ivysettings.xml

<ivysettings>
 <property name="ivy.local.default.root" 
              value="${ivy.default.ivy.user.dir}/local" override="false" />
 <property name="ivy.local.default.ivy.pattern" 
              value="[organisation]/[module]/ivys/ivy-[revision].xml" 
              override="false" />
 <property name="ivy.local.default.artifact.pattern" 
              value="[organisation]/[module]/[type]s/[artifact]-[revision].[ext]" 
              override="false" />
 <settings defaultResolver="myresolver" />
 <resolvers>
  <chain name="myresolver">
   <filesystem name="mylocal">
    <ivy 
                 pattern="${ivy.local.default.root}/${ivy.local.default.ivy.pattern}" />
    <artifact 
                 pattern="${ivy.local.default.root}/${ivy.local.default.artifact.pattern}" />
   </filesystem>
   <ibiblio name="mypublic" m2compatible="true" />
  </chain>
 </resolvers>
</ivysettings>

Our ivysettings.xml defines two resolvers within chain resolver
  • mylocal – filesystem based repository with root at $HOME/.ivy2/local as defined by variable ivy.local.default.root.
  • mypublic – default maven2 public repository.
Ivy pattern [organisation]/[module]/ivys/ivy-[revision].xml places ivy.xml in ivys directory. Artifact pattern [organisation]/[module]/[type]s/[artifact]-[revision].[ext] places jar, source and Javadoc artifacts in three subdirectories – jars, sources and javadocs. Even though all three artifacts are named as commons-lang-2.6.jar, Ivy distinguishes them from the directory where they are placed.
With those changes in settings, Ivy now has only three resolvers myresolver (chain), mylocal and mypublic. As default ivysettings.xml is not loaded, default resolver default, main, local, shared and public are not available.
In <ivy:install> task, we have to use mylocal and mypublic in from and to attributes. Add build.xml with these changes to work dir
build.xml

<project name="shared repository" default="install" 
 xmlns:ivy="antlib:org.apache.ivy.ant">
 <target name="install" description="local at non default location">
  <property name="ivy.local.default.ivy.pattern" 
         value="[organisation]/[module]/ivys/ivy-[revision].xml" />
  <property name="ivy.local.default.artifact.pattern" 
         value="[organisation]/[module]/[type]s/[artifact]-[revision].[ext]" />
  <ivy:install organisation="commons-lang" module="commons-lang" revision="2.6" 
            transitive="true" overwrite="false" from="mypublic" to="mylocal" />
 </target>
</project>

Delete the local repository and run Ant. Ivy Install task creates and populate the local repository using the custom resolvers from our ivysettings.xml.