Ivy Ant Tasks

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page walks through the Ant tasks that Apache Ivy 2.6.0 adds to Apache Ant 1.10.18: what each one does, every attribute that matters, what it leaves behind (properties, paths, files) and where it goes wrong. Every example was run on 2026-10-16 on JDK 26 (macOS) in a scratch copy of the dependency-management part of the tidepool-engine module, with Ivy’s cache and user directory inside that scratch directory so that no other build was touched. Console output is shown as printed, with the scratch path shortened to . and the machine name to host; examples that fetch from Maven Central show the revisions that were current on that day. What Ivy is, how it is installed and the vocabulary used here (organisation, module, revision, configuration) are on Ivy Overview; the ivy.xml files are explained on Ivy: Module Descriptors & Configurations, the resolvers on Ivy: Settings & Resolvers, and how versions are chosen on Ivy: Conflicts & Versions. The tasks that publish a module (deliver, publish, makepom, buildlist) are on Ivy: Publishing & Multi-Project Builds.

The scenario

The module is tidepool-engine, which reads station data with Commons CSV and, at run time only, uses picocli for its command line. Its descriptor declares three configurations: compile, runtime (which extends compile) and test (private, extends runtime):

ivy.xml
<ivy-module version="2.0">
  <info organisation="io.tidepool" module="tidepool-engine" revision="1.0.0" status="integration"/>
  <configurations>
    <conf name="compile" description="needed to compile"/>
    <conf name="runtime" extends="compile" description="needed to run"/>
    <conf name="test" extends="runtime" visibility="private" description="needed to test"/>
  </configurations>
  <publications>
    <artifact name="tidepool-engine" type="jar" conf="runtime"/>
  </publications>
  <dependencies defaultconfmapping="compile->default;runtime->default;test->default">
    <dependency org="org.apache.commons" name="commons-csv" rev="1.14.1" conf="compile"/>
    <dependency org="info.picocli" name="picocli" rev="4.7.+" conf="runtime"/>
    <dependency org="org.junit.jupiter" name="junit-jupiter-api" rev="5.11.4" conf="test"/>
  </dependencies>
</ivy-module>
ivysettings.xml
<ivysettings>
  <settings defaultResolver="central"/>
  <caches defaultCacheDir="${ivy.settings.dir}/build/ivy-cache"/>
  <resolvers>
    <ibiblio name="central" m2compatible="true"/>
  </resolvers>
</ivysettings>

And the head of the build file that every example below extends. The ivy XML namespace is how Ant finds the tasks; the Ivy JAR is put on Ant’s class path with -lib (other ways are on the overview page):

build.xml (head)
<project name="tidepool-engine" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
  <property name="lib.dir" location="build/lib"/>
  <property name="report.dir" location="build/ivy-report"/>
  <property name="ivy.default.ivy.user.dir" location="build/ivy-user"/>

  <target name="settings">
    <ivy:settings file="ivysettings.xml"/>
  </target>
  ...
</project>

Every command below is run as ant -lib lib/ivy-2.6.0.jar <target>.

ivy.default.ivy.user.dir is an Ant property that Ivy reads when it loads its settings: it replaces ~/.ivy2 as the per-user directory, and so as the home of the default cache. A check with the built-in default settings and this property set to build/ivy-user ended with the picocli JAR in build/ivy-user/cache/info.picocli/picocli/jars/picocli-4.7.7.jar. The examples on this page also set the cache in ivysettings.xml, which wins over the user directory for the cache, so they never touch the shared one.

The antlib defines these 32 task names in 2.6.0, read from the JAR’s antlib.xml: settings, resources, configure, resolve, retrieve, deliver, publish, extract, cachepath, cachefileset, report, repreport, var, check, artifactproperty, buildlist, install, convertpom, makepom, artifactreport, info, addpath, listmodules, findrevision, buildnumber, cleancache, buildobr, convertmanifest, fixdeps, dependencytree, checkdepsupdate and workspaceresolver. This page covers the dependency-resolution tasks; the OSGi-related ones (buildobr, convertmanifest), resources, extract, check, addpath, fixdeps and workspaceresolver are not used in the scenario and are not run here.

The files in this section are this page’s own setup for the examples that follow, not taken from the documentation.

How the tasks fit together

Ivy’s tasks fall into four groups, and most builds use only the first two:

flowchart LR S["settings / configure"] --> R["resolve"] R --> C[("Ivy cache")] C --> P["post-resolve tasks: retrieve, cachepath, cachefileset, artifactproperty, artifactreport, dependencytree, checkdepsupdate"] R --> RP["report"] S --> Q["queries: info, findrevision, listmodules, buildnumber"] S --> M["repository tasks: install, publish, deliver, makepom, convertpom"] C -. "cleancache" .-> X["empty cache"]
  • Settings load an ivysettings.xml (settings, configure) or set Ivy variables (var).

  • resolve reads an ivy.xml, finds every dependency in the repositories and stores the result in the cache.

  • Post-resolve tasks turn the cached result into something the build can use: copies (retrieve), an Ant path (cachepath), a fileset (cachefileset), properties (artifactproperty), an XML list (artifactreport) or console output (dependencytree, checkdepsupdate). report renders the resolution in HTML and GraphML.

  • Queries and repository tasks talk to the repositories without resolving a module: what is the newest 4.7 of picocli, what is this module’s metadata, copy a module from one repository to another.

Settings: settings and configure

Both tasks load an ivysettings.xml into an Ivy instance that the other tasks then share; file, url and id (the settingsId, default ivy.instance) are the attributes you use, and a task that needs a different configuration points to its instance with settingsRef. Credentials for HTTP resources go in host, realm, username and passwd or in nested credentials elements (shown on Ivy: Settings & Resolvers; in a build file, take the values from properties such as ${env.REPO_TOKEN}, never from literals).

The difference between the two is when the file is read:

Task Behaviour

settings (since 2.0)

A declaration. The file is loaded the first time some task needs it, so a typo is reported later, at that task.

configure

Loads the file immediately, so a problem is reported at the line that caused it. The override attribute (true, false or notallowed, the default) says what happens when an instance with the same id already exists.

Without file or url, both look for ${ivy.settings.file} (default ivysettings.xml) and fall back to Ivy’s built-in default settings, which resolve from Maven Central and use ~/.ivy2 for the cache. A missing file shows the difference:

build.xml
<target name="configure-bad">
  <ivy:configure file="does-not-exist.xml"/>
</target>
<target name="settings-bad">
  <ivy:settings file="does-not-exist.xml"/>
  <echo>settings declared; nothing loaded yet</echo>
  <ivy:info file="ivy.xml"/>
</target>
$ ant -lib lib/ivy-2.6.0.jar configure-bad
Buildfile: ./build.xml

configure-bad:
[ivy:configure] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::

BUILD FAILED
./build.xml:169: settings file does not exist: ./does-not-exist.xml

$ ant -lib lib/ivy-2.6.0.jar settings-bad
Buildfile: ./build.xml

settings-bad:
     [echo] settings declared; nothing loaded yet
 [ivy:info] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::

BUILD FAILED
./build.xml:175: settings file does not exist: ./does-not-exist.xml

The failure is reported on the line of the settings declaration, but only after the echo that follows it, because nothing had needed the settings yet. The same laziness explains a surprise with the default properties. Ivy defines a set of ivy.* properties (ivy.settings.file, ivy.dep.file=ivy.xml, ivy.retrieve.pattern and others) when it loads its first configuration, so a settings declaration alone has not defined them:

<target name="lazy-settings">
  <ivy:settings file="ivysettings.xml"/>
  <echo>after ivy:settings : ${ivy.retrieve.pattern}</echo>
  <ivy:configure file="ivysettings.xml" override="true"/>
  <echo>after ivy:configure: ${ivy.retrieve.pattern}</echo>
</target>
lazy-settings:
     [echo] after ivy:settings : ${ivy.retrieve.pattern}
[ivy:configure] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::
[ivy:configure] :: loading settings :: file = ./ivysettings.xml
     [echo] after ivy:configure: ./lib/[artifact]-[revision](-[classifier]).[ext]

The first echo shows the unexpanded ${...}, exactly as Ant leaves an undefined property. The default retrieve pattern in 2.6.0 already includes the optional (-[classifier]) part, so that a sources JAR does not overwrite the main one. The manual lists three places where a task attribute can be defined and consults them in this order: the task attribute itself, then the Ivy instance (the settings), then an Ant project property, so a property of your own is the weakest way to override a default. Ant’s own property rules are on Properties.

Ivy variables set in the settings file are also exposed to Ant as properties, under the plain name and under the name suffixed with . and the settings id, so two instances can carry different values of the same variable.

Source: Ivy: settings

Source: Ivy: configure

resolve

resolve reads the descriptor (file, default ${ivy.dep.file}, so ivy.xml), asks the resolvers for every dependency and its transitive dependencies in the chosen configurations (conf, default ${ivy.configurations}, which is *), and stores the result in the cache. It does not copy anything into the project.

Attribute Effect

file, conf

Descriptor to resolve and the comma-separated configurations to resolve. * is all, *(public) and *(private) pick by visibility.

refresh

true forces Ivy to recompute dynamic revisions (4.7.+, latest.release) instead of using the value cached by an earlier resolve. Default false.

resolveMode

default uses each dependency’s rev; dynamic uses its revConstraint. Without the attribute, the mode set in the settings applies.

transitive

false resolves only the direct dependencies. Default true.

type

Comma-separated artifact types to accept; the default comes from ${ivy.resolve.default.type.filter}, which is *.

haltonfailure, failureproperty

Whether an unresolved dependency fails the build (default true), and the property to set to true when it did not.

log

default (everything), download-only (nothing, except when something is downloaded) or quiet (only errors).

showprogress

false removes the dots printed while downloading.

validate

Force or skip validation of ivy.xml against ivy.xsd; the settings decide when unset.

resolveId

A name that later tasks use to refer to this resolution. The default is [org]-[module], the name of the module.

checkIfChanged, useCacheOnly

Compute ivy.deps.changed (default true; false saves a little time in multi-module builds), and forbid any repository access, using only what the caches know.

keep

Keep the result in memory for the post-resolve tasks. Default true for a descriptor, false for an inline resolve.

settingsRef

The settings instance to use.

After a resolve with a descriptor, Ivy sets ivy.organisation, ivy.module, ivy.revision and ivy.resolved.configurations (and the same names suffixed with . and the resolveId), plus ivy.deps.changed. For a module that extends a parent descriptor it also sets ivy.parents.count and ivy.parent[index].*.

What a resolve prints

The first resolve in a fresh cache, for the runtime configuration only and at the default log level:

<target name="resolve-default" depends="settings">
  <ivy:resolve file="ivy.xml" conf="runtime"/>
  <echo>ivy.deps.changed=${ivy.deps.changed}</echo>
</target>
$ ant -lib lib/ivy-2.6.0.jar resolve-default
Buildfile: ./build.xml

settings:

resolve-default:
[ivy:resolve] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::
[ivy:resolve] :: loading settings :: file = ./ivysettings.xml
[ivy:resolve] :: resolving dependencies :: io.tidepool#tidepool-engine;1.0.0
[ivy:resolve] 	confs: [runtime]
[ivy:resolve] 	found org.apache.commons#commons-csv;1.14.1 in central
[ivy:resolve] 	found commons-io#commons-io;2.20.0 in central
[ivy:resolve] 	found commons-codec#commons-codec;1.19.0 in central
[ivy:resolve] 	found info.picocli#picocli;4.7.7 in central
[ivy:resolve] 	[4.7.7] info.picocli#picocli;4.7.+
[ivy:resolve] downloading https://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.jar ...
[ivy:resolve] ...... (59kB)
[ivy:resolve] .. (0kB)
[ivy:resolve] 	[SUCCESSFUL ] org.apache.commons#commons-csv;1.14.1!commons-csv.jar (130ms)
[ivy:resolve] downloading https://repo1.maven.org/maven2/commons-io/commons-io/2.20.0/commons-io-2.20.0.jar ...
[ivy:resolve] ..................................... (550kB)
[ivy:resolve] .. (0kB)
[ivy:resolve] 	[SUCCESSFUL ] commons-io#commons-io;2.20.0!commons-io.jar (157ms)
[ivy:resolve] downloading https://repo1.maven.org/maven2/commons-codec/commons-codec/1.19.0/commons-codec-1.19.0.jar ...
[ivy:resolve] .......................... (365kB)
[ivy:resolve] .. (0kB)
[ivy:resolve] 	[SUCCESSFUL ] commons-codec#commons-codec;1.19.0!commons-codec.jar (126ms)
[ivy:resolve] downloading https://repo1.maven.org/maven2/info/picocli/picocli/4.7.7/picocli-4.7.7.jar ...
[ivy:resolve] ............................ (407kB)
[ivy:resolve] .. (0kB)
[ivy:resolve] 	[SUCCESSFUL ] info.picocli#picocli;4.7.7!picocli.jar (131ms)
[ivy:resolve] :: resolution report :: resolve 1773ms :: artifacts dl 544ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      runtime     |   4   |   4   |   4   |   0   ||   4   |   4   |
	---------------------------------------------------------------------
     [echo] ivy.deps.changed=true

Reading it top to bottom: the banner and the settings file in use; the module and configurations being resolved; one found line per module and the resolver that supplied it; the line [4.7.7] info.picocli#picocli;4.7.+ which is Ivy turning the dynamic revision 4.7.+ into a concrete one; the downloads; and the table. In the table, number is the number of modules in that configuration, transitive ones included, search how many needed a repository access, dwnlded how many descriptors were downloaded, evicted how many a conflict manager threw out, and the artifact columns count the files. Resolving runtime pulled in Commons IO and Commons Codec although the descriptor never mentions them: they are Commons CSV’s own dependencies, read from its POM.

The same command again, with everything in the cache:

[ivy:resolve] :: resolving dependencies :: io.tidepool#tidepool-engine;1.0.0
[ivy:resolve] 	confs: [runtime]
[ivy:resolve] 	found org.apache.commons#commons-csv;1.14.1 in central
[ivy:resolve] 	found commons-io#commons-io;2.20.0 in central
[ivy:resolve] 	found commons-codec#commons-codec;1.19.0 in central
[ivy:resolve] 	found info.picocli#picocli;4.7.7 in central
[ivy:resolve] 	[4.7.7] info.picocli#picocli;4.7.+
[ivy:resolve] :: resolution report :: resolve 65ms :: artifacts dl 4ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      runtime     |   4   |   0   |   0   |   0   ||   4   |   0   |
	---------------------------------------------------------------------
     [echo] ivy.deps.changed=false

No searches, no downloads, and ivy.deps.changed=false. That property is the cheap way to skip work in a build: when it is false the dependencies are exactly what the previous resolve produced. Note that 4.7.+ was not looked up again: a dynamic revision resolved once is remembered by the cache until its time to live runs out (10 seconds by default) or you pass refresh="true" (the TTL is covered on Ivy: Settings & Resolvers).

Source: Ivy: resolve

Log levels

log="download-only" is the usual choice for a build you run all day: silent when the cache is warm, informative when something is fetched. log="quiet" prints only problems. The two-line target below resolves two configurations quietly:

<target name="resolve-quiet" depends="settings">
  <ivy:resolve file="ivy.xml" conf="compile,runtime" log="quiet" showprogress="false"/>
  <echo>resolved ${ivy.resolved.configurations}</echo>
</target>
$ ant -q -lib lib/ivy-2.6.0.jar resolve-quiet
     [echo] resolved compile, runtime

Inline mode

Without a descriptor, inline="true" resolves one module named by organisation, module and revision (the revision defaults to latest.integration). Its usual job is to fetch a tool that the build itself needs, such as an Ant task library, before the real build starts. The post-resolve tasks accept the same attributes, so a single cachepath can resolve and build the path:

<target name="resolve-inline" depends="settings">
  <ivy:cachepath organisation="org.apache.commons" module="commons-lang3" revision="3.18.0"
                 inline="true" conf="default" pathid="lang3.path" log="quiet"/>
  <pathconvert property="lang3.files" pathsep="${line.separator}" refid="lang3.path">
    <map from="${ivy.settings.dir}/build/ivy-cache" to="CACHE"/>
  </pathconvert>
  <echo>${lang3.files}</echo>
</target>
     [echo] CACHE/org.apache.commons/commons-lang3/jars/commons-lang3-3.18.0.jar

Two points. An inline resolve is not kept (keep defaults to false), so ivy.revision and friends are not set and a later retrieve cannot reuse it; set keep="true" if you need that. And the attribute pathid does not exist on resolve: an attempt to put it there is rejected with ivy:resolve doesn't support the "pathid" attribute, because the path is created by the post-resolve task, not by the resolve.

Dependencies written inside the task

Since 2.3 a resolve (and every post-resolve task) can hold nested dependency, exclude, override and conflict elements instead of reading a file. There is no master configuration in this form, so there is only one configuration to resolve and a conf attribute on a nested dependency names a configuration of the dependency, not a mapping:

<target name="inline-deps" depends="settings">
  <ivy:resolve conf="default" log="quiet">
    <dependency org="org.apache.commons" name="commons-csv" rev="1.14.1" conf="default"/>
    <exclude org="commons-codec"/>
  </ivy:resolve>
  <ivy:cachepath pathid="inline.path" conf="default"/>
  <pathconvert property="inline.files" pathsep="${line.separator}" refid="inline.path">
    <map from="${ivy.settings.dir}/build/ivy-cache/" to="CACHE/"/>
  </pathconvert>
  <echo>${inline.files}</echo>
</target>
     [echo] CACHE/org.apache.commons/commons-csv/jars/commons-csv-1.14.1.jar
     [echo] CACHE/commons-io/commons-io/jars/commons-io-2.20.0.jar

The exclude removed Commons Codec. The same build with conf="default" left off the nested dependency resolved every configuration of the Commons CSV POM, including its test scope and optional dependencies: 23 JARs, among them JUnit, Mockito, H2 and JMH, and the javadocs and sources JARs. That is a classic first-day mistake with Maven modules in Ivy; the default mapping of a Maven module’s configurations is explained with the descriptors, on Ivy: Module Descriptors & Configurations.

When a dependency is not found

An unresolvable dependency is reported in a "problems summary" that lists every URL that was tried. With haltonfailure="false" and a failureproperty the build can carry on and decide for itself:

<target name="unresolved" depends="settings">
  <ivy:resolve conf="default" haltonfailure="false" failureproperty="resolve.failed" log="default">
    <dependency org="org.apache.commons" name="commons-csv" rev="9.9.9"/>
  </ivy:resolve>
  <echo>resolve.failed=${resolve.failed}</echo>
</target>
unresolved:
[ivy:resolve] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::
[ivy:resolve] :: loading settings :: file = ./ivysettings.xml
[ivy:resolve] :: resolving dependencies :: #;working@host
[ivy:resolve] 	confs: [default]
[ivy:resolve] :: resolution report :: resolve 635ms :: artifacts dl 0ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      default     |   1   |   0   |   0   |   0   ||   0   |   0   |
	---------------------------------------------------------------------
[ivy:resolve]
[ivy:resolve] :: problems summary ::
[ivy:resolve] :::: WARNINGS
[ivy:resolve] 		module not found: org.apache.commons#commons-csv;9.9.9
[ivy:resolve] 	==== central: tried
[ivy:resolve] 	  https://repo1.maven.org/maven2/org/apache/commons/commons-csv/9.9.9/commons-csv-9.9.9.pom
[ivy:resolve] 	  -- artifact org.apache.commons#commons-csv;9.9.9!commons-csv.jar:
[ivy:resolve] 	  https://repo1.maven.org/maven2/org/apache/commons/commons-csv/9.9.9/commons-csv-9.9.9.jar
[ivy:resolve] 		::::::::::::::::::::::::::::::::::::::::::::::
[ivy:resolve] 		::          UNRESOLVED DEPENDENCIES         ::
[ivy:resolve] 		::::::::::::::::::::::::::::::::::::::::::::::
[ivy:resolve] 		:: org.apache.commons#commons-csv;9.9.9: not found
[ivy:resolve] 		::::::::::::::::::::::::::::::::::::::::::::::
[ivy:resolve]
[ivy:resolve] :: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS
     [echo] resolve.failed=true

The module with no descriptor of its own is named #, which is why the line says #;working@host. With the default haltonfailure="true" the same resolve ends the build:

BUILD FAILED
./build.xml:116: impossible to resolve dependencies:
	resolve failed - see output for details

The messages to look for in a real project are the tried lists (they tell you exactly which patterns the resolver built, which is the quickest way to debug a wrong pattern), module not found for a missing revision and download failed when the descriptor was found but the JAR was not.

Concurrency: not inside parallel

Ivy keeps per-resolution files in the resolution cache, and a resolve is "not aimed to support concurrency": two concurrent resolves of the same module in the same cache with the same resolveId are not supported. Ant’s parallel task makes exactly that easy to do by accident. Three resolves of the same descriptor in a parallel block, with a cold cache:

<target name="parallel-resolve" depends="settings">
  <parallel>
    <ivy:resolve file="ivy.xml" conf="compile" log="quiet"/>
    <ivy:resolve file="ivy.xml" conf="runtime" log="quiet"/>
    <ivy:resolve file="ivy.xml" conf="test" log="quiet"/>
  </parallel>
</target>
[ivy:resolve] :: problems summary ::
[ivy:resolve] :::: WARNINGS
[ivy:resolve] 	problem while downloading module descriptor: https://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.pom: ./build/ivy-cache/org.apache.commons/commons-csv/ivy-1.14.1.xml.original.part (No such file or directory) (136ms)
[ivy:resolve] 		module not found: org.apache.commons#commons-csv;1.14.1
[ivy:resolve] 	==== central: tried
[ivy:resolve] 	  https://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.pom

This was run three times from an empty cache and failed every time, with a different module "not found" depending on which thread lost the race, although the artifact exists. The rule is therefore: resolve once, before the parallel part, and let the parallel targets use retrieve or cachepath on the result, or give each branch its own cache. (The same restriction is why Ivy is documented as not thread-safe on Ivy Overview.)

Source: Ivy: resolve

Post-resolve tasks

retrieve, cachepath, cachefileset, artifactproperty, artifactreport, dependencytree and checkdepsupdate are post-resolve tasks: they work on the result of a resolve and share a set of attributes. If no resolve has been kept in this build and no organisation and module are given, they run one themselves, using the shared attributes file, conf, refresh, resolveMode, transitive, haltonfailure, validate, inline, keep, log and settingsRef. conf defaults to the configurations of the last resolve. To reuse a resolve from an earlier Ant run, name its organisation and module; that works as long as the cache was not cleaned, and not for inline resolves.

The manual recommends retrieve plus ordinary Ant paths over the cache-based tasks (cachepath, cachefileset, artifactproperty), because a build that works from retrieved files no longer needs Ivy to compile.

retrieve

retrieve copies the resolved artifacts out of the cache into the project, following a pattern in which these tokens are replaced: [organisation], [orgPath] (the organisation with dots turned into directories), [module], [branch], [revision], [artifact], [type], [ext], [conf] and any extra attribute in brackets, with ( ) marking an optional part that disappears when its token has no value. The pattern must give every artifact a unique file name.

Attribute Effect

pattern

Where files go; the default is ${ivy.retrieve.pattern}.

conf, type

Retrieve only these configurations and artifact types (all by default).

sync

Delete everything under the pattern’s root directory that the retrieve did not just place there. Default false.

overwriteMode

newer (default, since 2.2), different, always or never.

symlink

Create symbolic links instead of copies, falling back to a copy when the file system refuses. (The older symlinkmass is deprecated since 2.5 and ignored.)

ivypattern

Also copy the descriptors of the dependencies, using this pattern.

pathId, setId

Create an Ant path or fileset of the retrieved files (since 2.3).

log

default or quiet for the retrieve step.

The most common form separates files by configuration, so that the compile class path and the run-time class path are two directories:

<target name="retrieve" depends="resolve">
  <ivy:retrieve pattern="${lib.dir}/[conf]/[artifact]-[revision].[ext]" sync="true" type="jar"/>
  ...
</target>
$ ant -lib lib/ivy-2.6.0.jar retrieve
[ivy:retrieve] :: retrieving :: io.tidepool#tidepool-engine [sync]
[ivy:retrieve] 	confs: [compile, runtime, test]
[ivy:retrieve] 	15 artifacts copied, 0 already retrieved (4115kB/10ms)
     [echo] compile/commons-codec-1.19.0.jar
     [echo] compile/commons-csv-1.14.1.jar
     [echo] compile/commons-io-2.20.0.jar
     [echo] runtime/commons-codec-1.19.0.jar
     [echo] runtime/commons-csv-1.14.1.jar
     [echo] runtime/commons-io-2.20.0.jar
     [echo] runtime/picocli-4.7.7.jar
     [echo] test/apiguardian-api-1.1.2.jar
     [echo] test/commons-codec-1.19.0.jar
     [echo] test/commons-csv-1.14.1.jar
     [echo] test/commons-io-2.20.0.jar
     [echo] test/junit-jupiter-api-5.11.4.jar
     [echo] test/junit-platform-commons-1.11.4.jar
     [echo] test/opentest4j-1.3.0.jar
     [echo] test/picocli-4.7.7.jar

A JAR that belongs to three configurations is copied three times (15 files for 8 distinct JARs). That is the price of the [conf] token, and the reason many builds retrieve only runtime into a flat directory for packaging and use cachepath for compiling. The summary line also shows the "already retrieved" count: a second run copies nothing.

sync is destructive. The root of the synchronisation is the first directory in the pattern that contains no token, here build/lib. Everything under it that this retrieve did not place is deleted, including what another retrieve put there. A stray file next to the retrieved ones disappears:

$ touch build/lib/compile/stray.jar
$ ant -lib lib/ivy-2.6.0.jar retrieve
[ivy:retrieve] :: retrieving :: io.tidepool#tidepool-engine [sync]
[ivy:retrieve] 	confs: [compile, runtime, test]
[ivy:retrieve] 	0 artifacts copied, 15 already retrieved (0kB/4ms)
$ ls build/lib/compile
commons-codec-1.19.0.jar
commons-csv-1.14.1.jar
commons-io-2.20.0.jar

And a second, differently shaped retrieve into the same root wipes the first one. After the 15-file retrieve above, this one for runtime only into a flat layout:

<ivy:retrieve pattern="${lib.dir}/[artifact]-[revision].[ext]" conf="runtime" sync="true"/>
[ivy:retrieve] :: retrieving :: io.tidepool#tidepool-engine [sync]
[ivy:retrieve] 	confs: [runtime]
[ivy:retrieve] 	4 artifacts copied, 0 already retrieved (1384kB/4ms)

find build/lib -type f then listed only picocli-4.7.7.jar, commons-csv-1.14.1.jar, commons-codec-1.19.0.jar and commons-io-2.20.0.jar: the compile/, runtime/ and test/ copies were gone. Use a distinct root per retrieve (build/lib/runtime, build/lib/test) whenever you synchronise.

The [type] and [organisation] tokens, the pathId/setId attributes and an organisation-per-directory layout together:

<ivy:retrieve pattern="${lib.dir}/[type]/[organisation]/[artifact]-[revision].[ext]" conf="runtime"
              sync="true" pathId="retrieved.path" setId="retrieved.set" log="quiet"/>
     [echo] jar/commons-codec/commons-codec-1.19.0.jar
     [echo] jar/commons-io/commons-io-2.20.0.jar
     [echo] jar/info.picocli/picocli-4.7.7.jar
     [echo] jar/org.apache.commons/commons-csv-1.14.1.jar

Mappers. A nested Ant mapper (since 2.3) rewrites the destination path of each file. The path it sees is the absolute one, so a globmapper pattern has to start with the full directory (and a glob mapper accepts a single *):

<ivy:retrieve pattern="${lib.dir}/mapped/[artifact]-[revision].[ext]" conf="runtime" sync="true">
  <firstmatchmapper>
    <globmapper from="${lib.dir}/mapped/commons-*" to="${lib.dir}/mapped/commons/commons-*"/>
    <globmapper from="${lib.dir}/mapped/*" to="${lib.dir}/mapped/other/*"/>
  </firstmatchmapper>
</ivy:retrieve>
[ivy:retrieve] :: retrieving :: io.tidepool#tidepool-engine [sync]
[ivy:retrieve] 	confs: [runtime]
[ivy:retrieve] 	4 artifacts copied, 0 already retrieved (1384kB/4ms)
     [echo] mapped/commons/commons-codec-1.19.0.jar
     [echo] mapped/commons/commons-csv-1.14.1.jar
     [echo] mapped/commons/commons-io-2.20.0.jar
     [echo] mapped/other/picocli-4.7.7.jar

A first attempt with a relative from (build/lib/mapped/commons-*) matched nothing and the log said 0 artifacts copied: a mapper that does not match drops the file rather than keeping its original name. If the output directory is empty after a retrieve with a mapper, check the from patterns first.

Source: Ivy: retrieve

cachepath and cachefileset

cachepath builds an Ant path (pathid, required) from the cached files of the chosen configurations (conf, type), and useOrigin="true" points to the original location of local artifacts instead of copying them into the cache. It is the shortest way to get a class path:

<target name="cachepath" depends="resolve">
  <ivy:cachepath pathid="runtime.path" conf="runtime"/>
  <pathconvert property="runtime.files" pathsep="${line.separator}" refid="runtime.path">
    <map from="${ivy.settings.dir}/build/ivy-cache/" to="CACHE/"/>
  </pathconvert>
  <echo>${runtime.files}</echo>
</target>
     [echo] CACHE/org.apache.commons/commons-csv/jars/commons-csv-1.14.1.jar
     [echo] CACHE/commons-io/commons-io/jars/commons-io-2.20.0.jar
     [echo] CACHE/commons-codec/commons-codec/jars/commons-codec-1.19.0.jar
     [echo] CACHE/info.picocli/picocli/jars/picocli-4.7.7.jar

The path has no duplicates even though three configurations share some JARs. The order follows the dependency order of the resolution, which matters when two libraries contain the same class.

cachefileset (setid, conf, type) builds a fileset instead, for tasks that want one, such as jar or copy:

<ivy:cachefileset setid="compile.set" conf="compile"/>
     [echo] CACHE/commons-codec/commons-codec/jars/commons-codec-1.19.0.jar
     [echo] CACHE/commons-io/commons-io/jars/commons-io-2.20.0.jar
     [echo] CACHE/org.apache.commons/commons-csv/jars/commons-csv-1.14.1.jar

A fileset needs one base directory, so cachefileset looks for a common ancestor of all the cached files and builds the set below it; the manual describes the limitation that results when no common directory exists. Prefer cachepath for class paths and retrieve for anything you ship.

Source: Ivy: cachepath

artifactproperty

artifactproperty sets one Ant property per resolved artifact. name and value are patterns, so the property name can be built from the module and the revision and the value can be the path where retrieve put the file:

<target name="artifactproperty" depends="resolve">
  <ivy:artifactproperty conf="runtime" name="[module].[artifact]-[revision]"
                        value="${lib.dir}/[artifact]-[revision].[ext]"/>
  <echo>${commons-csv.commons-csv-1.14.1}</echo>
  <echo>${picocli.picocli-4.7.7}</echo>
</target>
     [echo] ./build/lib/commons-csv-1.14.1.jar
     [echo] ./build/lib/picocli-4.7.7.jar

Since 2.0 the task follows Ant’s rule that a property is not overwritten; before 2.0 it always overwrote. Set overwrite="true" to get the old behaviour.

artifactreport

artifactreport writes one XML file listing every resolved artifact with its origin location, its cache location and the location a retrieve with the given pattern would use. It is meant for generating IDE class path files:

<ivy:artifactreport tofile="build/artifact-report.xml" conf="compile"
                    pattern="${lib.dir}/[artifact]-[revision].[ext]"/>
<modules>
    <module organisation="org.apache.commons" name="commons-csv" rev="1.14.1" status="release">
        <artifact name="commons-csv" ext="jar" type="jar">
            <origin-location is-local="false">https://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.jar</origin-location>
            <cache-location>./build/ivy-cache/org.apache.commons/commons-csv/jars/commons-csv-1.14.1.jar</cache-location>
            <retrieve-location>build/lib/commons-csv-1.14.1.jar</retrieve-location>
        </artifact>
    </module>
    ...
</modules>

Looking at the result

report

report renders the XML that resolve stored in the cache as one HTML page per configuration, with links between them, and as GraphML files that the free yEd editor can lay out. It needs a resolve of the same module and configurations in the cache, though not necessarily in this build.

Attribute Effect

todir, outputpattern

Output directory (default ${ivy.report.todir} or the current directory) and the file name pattern, default [organisation]-[module]-[conf].[ext].

conf

Configurations to report on; by default those of the last resolve.

xsl, xslfile, xslext

Generate the report with XSLT (default true, with Ivy’s own stylesheet producing HTML); supply your own stylesheet and extension, with nested param elements for its parameters.

xml

Also keep the raw XML (default false).

graph, dot

GraphML files (default true) and Graphviz DOT files (default false, since 1.4).

organisation, module, resolveId

Needed to report on a resolve from an earlier run.

<target name="report" depends="resolve">
  <ivy:report todir="${report.dir}" conf="runtime,test"/>
  <ivy:report todir="${report.dir}/xml-only" outputpattern="[organisation]-[module]-[conf].[ext]" xml="true" xsl="false"/>
</target>
$ ls build/ivy-report build/ivy-report/xml-only
build/ivy-report:
io.tidepool-tidepool-engine-runtime.graphml
io.tidepool-tidepool-engine-runtime.html
io.tidepool-tidepool-engine-test.graphml
io.tidepool-tidepool-engine-test.html
ivy-report.css
xml-only

build/ivy-report/xml-only:
io.tidepool-tidepool-engine-compile.graphml
io.tidepool-tidepool-engine-compile.xml
io.tidepool-tidepool-engine-runtime.graphml
io.tidepool-tidepool-engine-runtime.xml
io.tidepool-tidepool-engine-test.graphml
io.tidepool-tidepool-engine-test.xml
The HTML page is titled "Ivy report

tidepool-engine by io.tidepool :: runtime" and shows, for each module, its revision, the resolver that supplied it, its licence and whether it was downloaded or searched. The XML form (one file per configuration, here with the [conf] name in the file name) carries the same data and also lists the callers of each module, with rev-constraint-default and rev-constraint-dynamic for each, which is the first place to look when a version is not what you expected. It contains absolute paths of the cache, so read it with a tool rather than committing it.

repreport is the repository-wide version of the same idea: it reports on a set of modules in a repository rather than on one resolve. It needs a resolver that can list its contents and, with m2compatible, cannot list organisations at all. Run against the Maven Central settings above it resolved "0 modules" and wrote an empty ivy-repository-report.xml, as the manual says it would; it is useful with an Ivy-layout file or URL repository (an example is on Ivy: Publishing & Multi-Project Builds).

Source: Ivy: report

Source: Ivy: repreport

dependencytree

dependencytree prints the resolved graph on the console (conf, showEvicted). It shows a module by its requested revision, so the dynamic 4.7.+ is printed rather than 4.7.7, and in 2.6.0 it prints a module once for each way it was reached, so the same node can appear several times. Read it as a tree, not as a count:

<ivy:dependencytree conf="runtime"/>
[ivy:dependencytree] Dependency tree for io.tidepool-tidepool-engine
[ivy:dependencytree] +- org.apache.commons#commons-csv;1.14.1
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] +- org.apache.commons#commons-csv;1.14.1
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] +- org.apache.commons#commons-csv;1.14.1
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-io#commons-io;2.20.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] |  +- commons-codec#commons-codec;1.19.0
[ivy:dependencytree] +- info.picocli#picocli;4.7.+
[ivy:dependencytree] +- info.picocli#picocli;4.7.+
[ivy:dependencytree] \- org.junit.jupiter#junit-jupiter-api;5.11.4
[ivy:dependencytree] |  +- org.opentest4j#opentest4j;1.3.0
[ivy:dependencytree] |  +- org.junit.platform#junit-platform-commons;1.11.4
[ivy:dependencytree] |     \- org.apiguardian#apiguardian-api;1.1.2
[ivy:dependencytree]    \- org.apiguardian#apiguardian-api;1.1.2

The repetition above is real output: the tree is printed from the resolution of every configuration, and the last lines belong to the test configuration even though conf="runtime" was asked for. For a readable graph use the HTML report; use dependencytree for a quick look at "who brings in what" when a resolve surprises you.

checkdepsupdate

checkdepsupdate asks the repositories for the newest revision of each dependency (revisionToCheck, default latest.integration) and prints those that are newer than the descriptor’s. showTransitive="true" includes transitive modules, and download="true" fetches the new artifacts.

<ivy:checkdepsupdate showTransitive="false"/>
[ivy:checkdepsupdate] Dependencies updates available :
[ivy:checkdepsupdate] 	org.junit.jupiter#junit-jupiter-api	5.11.4 -> 6.1.3

The newer revision is reported as is, major versions included: the JUnit line moved from 5.x to 6.x between the descriptor and the day of the run. Commons CSV was already the newest revision and picocli’s range 4.7.+ already denotes its newest 4.7, so neither is listed. The report is advisory; it changes nothing.

Asking questions without resolving

info

info reads a descriptor without resolving anything and sets properties for its content, so a build can learn its own coordinates from ivy.xml instead of repeating them:

<target name="info">
  <ivy:info file="ivy.xml"/>
  <echo>${ivy.organisation}#${ivy.module};${ivy.revision} status=${ivy.status}</echo>
  <echo>configurations=${ivy.configurations}</echo>
  <echo>public=${ivy.public.configurations}</echo>
</target>
     [echo] io.tidepool#tidepool-engine;1.0.0 status=integration
     [echo] configurations=compile, runtime, test
     [echo] public=compile, runtime

The other properties are ivy.branch, ivy.publication, ivy.extra.[attribute], ivy.configuration.[name].desc, and, for each published artifact, ivy.artifact.[index].name, .type, .ext, .conf and .extra.[attribute]. The test configuration is private, so it is in ivy.configurations but not in ivy.public.configurations.

With organisation, module and revision (and no file), the task reads the metadata of a module in a repository, and property changes the prefix of the names it sets (default ivy):

<ivy:info organisation="org.apache.commons" module="commons-csv" revision="1.14.1" property="csv"/>
<echo>${csv.organisation}#${csv.module};${csv.revision} status=${csv.status}</echo>
     [echo] org.apache.commons#commons-csv;1.14.1 status=release

If no module matches, no property is set at all, so test with if/unless or a condition before using the values. Every property that info sets is overwritten by a later info, which the next section uses.

Source: Ivy: info

findrevision

findrevision returns the newest revision matching a constraint. It is the quick way to learn what 4.7.+ or latest.release means today, without resolving anything:

<target name="findrevision" depends="settings">
  <ivy:findrevision organisation="info.picocli" module="picocli" revision="4.7.+" property="picocli.latest"/>
  <echo>picocli 4.7.+ is ${picocli.latest}</echo>
  <ivy:findrevision organisation="org.apache.commons" module="commons-csv" revision="latest.release" property="csv.latest"/>
  <echo>commons-csv latest.release is ${csv.latest}</echo>
</target>
     [echo] picocli 4.7.+ is 4.7.7
     [echo] commons-csv latest.release is 1.14.1

Without property the task sets ivy.revision. It is subsumed by the repository form of info, which sets more.

buildnumber

buildnumber is Ivy’s counterpart of Ant’s own buildnumber task (described on Utility Tasks, which keeps its counter in a local file): it asks the repository for the latest revision that starts with a prefix and computes the next one. It sets ivy.revision, ivy.new.revision, ivy.build.number and ivy.new.build.number (use prefix to change ivy). With revision="4.7." (the trailing dot restricts it to the 4.7 line) against the picocli versions on Maven Central:

<ivy:buildnumber organisation="info.picocli" module="picocli" revision="4.7."/>
<echo>revision=${ivy.revision} new=${ivy.new.revision} build=${ivy.build.number} newbuild=${ivy.new.build.number}</echo>
     [echo] revision=4.7.7 new=4.7.8 build=7 newbuild=8

The rules, with the manual’s examples checked against Ivy 2.6.0 on a filesystem repository whose newest revision is 1.3.1: revision="1.3" or no prefix gives the new revision 1.3.2 and build numbers 1 and 2, revision="1." and revision="1" both give 1.4 (build numbers 3 and 4), and revision="3." gives 3.0 with new build number 0. For revision="1.2" (a prefix with no existing revision) the manual’s prose example says 1.2.1, but Ivy 2.6.0 gives 1.2.0, because the first build number is defaultBuildNumber, which defaults to 0; the manual’s own table agrees (2 gives 2.0). A prefix without the trailing dot also matches 10.0 when you ask for 1, so use versions with the same number of parts. defaultBuildNumber, revSep and default handle the first release, as in revision="1.4-RC" defaultBuildNumber="1" revSep="" giving 1.4-RC1, 1.4-RC2, and so on. resolver limits the search to one resolver (since 2.1), which you want in a chain that includes a snapshot repository. Used with a publication repository it turns "next release" into something the build can compute; see Ivy: Publishing & Multi-Project Builds for the full loop.

listmodules

listmodules sets one property per module found in the repository that matches patterns for organisation, module, branch and revision; property and value are patterns over those tokens. It needs a resolver that can list its contents. The default matcher is exactOrRegexp; the glob matcher (a natural choice) needs the Jakarta ORO library, which is not bundled with Ivy:

BUILD FAILED
./build.xml:127: java.lang.NoClassDefFoundError: org/apache/oro/text/regex/MalformedPatternException
	at org.apache.ivy.plugins.matcher.GlobPatternMatcher.newMatcher(GlobPatternMatcher.java:57)
	...
Caused by: java.lang.ClassNotFoundException: org.apache.oro.text.regex.MalformedPatternException

Adding oro:oro:2.0.8 to the Ant class path (-lib lib/oro-2.0.8.jar) cures that. Listing a Maven-layout repository is much less reliable than listing an Ivy-layout one, though: on a filesystem resolver with m2compatible holding three modules, a listmodules for the organisation org.apache.commons returned commons-codec and commons-io but not commons-csv, so do not build decisions on it for Maven repositories. For an Ivy-layout repository it is dependable; the example is on Ivy: Publishing & Multi-Project Builds.

Variables and the cache

var

var sets an Ivy variable (one name and value, or a whole file or url of properties, with an optional prefix). Unlike Ant properties, Ivy variables can be changed, but Ivy substitutes them as soon as it can, so changing a variable after a file was read has no effect on that file. The manual therefore advises against the task. It is visible in a descriptor read after the variable was set, since a descriptor can use ${name}:

ivy-var.xml
<ivy-module version="2.0">
  <info organisation="io.tidepool" module="tidepool-engine" revision="${build.rev}" status="integration"/>
</ivy-module>
<target name="var">
  <ivy:var name="build.rev" value="1.0.0-SNAPSHOT"/>
  <ivy:info file="ivy-var.xml"/>
  <echo>first : ${ivy.revision}</echo>
  <ivy:var name="build.rev" value="1.0.0-rc1"/>
  <ivy:info file="ivy-var.xml"/>
  <echo>second: ${ivy.revision}</echo>
</target>
var:
  [ivy:var] :: Apache Ivy 2.6.0 - 20260712075753 :: https://ant.apache.org/ivy/ ::
  [ivy:var] :: loading settings :: file = ./ivysettings.xml
     [echo] first : 1.0.0-SNAPSHOT
     [echo] second: 1.0.0-rc1

Two details. var loads the default settings if none are loaded, so it counts as the first Ivy task for the lazy-loading rule above. And ivy.revision changed from the first info to the second although it is an Ant property, because the ivy.* properties that info sets are written with overwrite. An attempt to set a variable after a settings file had been declared and then used it as a resolver name in that file left the name unsubstituted (the resolve reported found ... in ${repo.name}), which is the substitution-timing problem the manual warns about. Treat var as a way to feed descriptors, not settings files.

Source: Ivy: var

cleancache

cleancache empties the cache that the settings define, roughly <delete dir="${ivy.cache.dir}"/>, but through a settings instance (settingsRef), so it empties the right cache in a build with several. Because it deletes the cache that every other build on the machine may share, point it only at a private cache, as here:

ivysettings-tmp.xml
<ivysettings>
  <settings defaultResolver="central"/>
  <caches defaultCacheDir="${ivy.settings.dir}/build/tmp-cache"/>
  <resolvers>
    <ibiblio name="central" m2compatible="true"/>
  </resolvers>
</ivysettings>
<target name="cleancache">
  <ivy:settings file="ivysettings-tmp.xml" id="tmp.settings"/>
  <ivy:cachepath organisation="info.picocli" module="picocli" revision="4.7.7" inline="true" conf="default"
                 pathid="tmp.path" settingsRef="tmp.settings" log="quiet"/>
  <condition property="cache.present"><available file="build/tmp-cache/info.picocli" type="dir"/></condition>
  <echo>before cleancache: cache has picocli = ${cache.present}</echo>
  <ivy:cleancache settingsRef="tmp.settings"/>
  <condition property="cache.present.after" value="true" else="false"><available file="build/tmp-cache/info.picocli" type="dir"/></condition>
  <echo>after cleancache:  cache has picocli = ${cache.present.after}</echo>
</target>
     [echo] before cleancache: cache has picocli = true
     [echo] after cleancache:  cache has picocli = false

Cleaning the cache is the cure for most "it works on my machine" resolution problems and for corrupt downloads; the lock and cache strategies behind it are on Ivy: Settings & Resolvers.

Source: Ivy: cleancache

Moving modules between repositories

install

install copies a module, optionally with its transitive dependencies, from one resolver (from) into another (to) that supports publishing, using the metadata and artifacts that Ivy finds. The classic use is a private repository that has only what your projects need: when a library is missing there, install it from a public one. Both resolvers are named in the settings; here a read-only central and a filesystem resolver called private, in Maven layout:

ivysettings-install.xml
<ivysettings>
  <settings defaultResolver="central"/>
  <caches defaultCacheDir="${ivy.settings.dir}/build/install-cache"/>
  <resolvers>
    <ibiblio name="central" m2compatible="true"/>
    <filesystem name="private" m2compatible="true">
      <artifact pattern="${ivy.settings.dir}/build/private-repo/[orgPath]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"/>
      <ivy pattern="${ivy.settings.dir}/build/private-repo/[orgPath]/[module]/[revision]/[module]-[revision].pom"/>
    </filesystem>
  </resolvers>
</ivysettings>
<target name="install" depends="settings">
  <ivy:settings file="ivysettings-install.xml" id="install.settings"/>
  <ivy:install organisation="org.apache.commons" module="commons-csv" revision="1.14.1"
               from="central" to="private" conf="default" transitive="true" overwrite="true"
               settingsRef="install.settings"/>
  ...
</target>
[ivy:install] 	found commons-codec#commons-codec;1.19.0 in central
[ivy:install] :: downloading artifacts to cache ::
[ivy:install] downloading https://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.jar ...
[ivy:install] ............... (59kB)
[ivy:install] .. (0kB)
[ivy:install] 	[SUCCESSFUL ] org.apache.commons#commons-csv;1.14.1!commons-csv.jar (124ms)
[ivy:install] downloading https://repo1.maven.org/maven2/commons-io/commons-io/2.20.0/commons-io-2.20.0.jar ...
[ivy:install] .................................... (550kB)
[ivy:install] .. (0kB)
[ivy:install] 	[SUCCESSFUL ] commons-io#commons-io;2.20.0!commons-io.jar (157ms)
[ivy:install] downloading https://repo1.maven.org/maven2/commons-codec/commons-codec/1.19.0/commons-codec-1.19.0.jar ...
[ivy:install] ......................... (365kB)
[ivy:install] .. (0kB)
[ivy:install] 	[SUCCESSFUL ] commons-codec#commons-codec;1.19.0!commons-codec.jar (123ms)
[ivy:install] :: installing in private ::
[ivy:install] 	published commons-csv to ./build/private-repo/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.jar
[ivy:install] 	published ivy to ./build/private-repo/org/apache/commons/commons-csv/1.14.1/commons-csv-1.14.1.pom
[ivy:install] 	published commons-io to ./build/private-repo/commons-io/commons-io/2.20.0/commons-io-2.20.0.jar
[ivy:install] 	published ivy to ./build/private-repo/commons-io/commons-io/2.20.0/commons-io-2.20.0.pom
[ivy:install] 	published commons-codec to ./build/private-repo/commons-codec/commons-codec/1.19.0/commons-codec-1.19.0.jar
[ivy:install] 	published ivy to ./build/private-repo/commons-codec/commons-codec/1.19.0/commons-codec-1.19.0.pom
[ivy:install] :: install resolution report ::
[ivy:install] :: resolution report :: resolve 0ms :: artifacts dl 406ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      default     |   3   |   3   |   3   |   0   ||   3   |   3   |
	---------------------------------------------------------------------

The repository then held, for each of the three modules, the JAR and a POM plus the .md5 and .sha1 checksum files that Ivy writes beside each (commons-csv-1.14.1.jar, .jar.md5, .jar.sha1, .pom, .pom.md5, .pom.sha1, and likewise for Commons IO and Commons Codec), 18 files in total. The installOriginalMetadata attribute (since 2.4) copies the original POM when the module came from a Maven repository instead of the descriptor Ivy converted from it; that is what a Maven-layout target should receive, and it is the safer choice when the installed repository will also be read by Maven.

An earlier run of the same task for commons-lang3 without conf installed that module’s test and optional configurations too, and the repository ended up holding JUnit, Mockito, JMH and ASM, which is why conf (since 2.3) is worth setting. The attributes type (artifact types, default all), matcher (to install several modules with a pattern), validate, haltonfailure and branch complete the task.

Source: Ivy: install

convertpom

convertpom writes an ivy.xml from a pom.xml (pomFile, ivyFile, both required). It is the first step of an Ivy-to-Maven or Maven-to-Ivy move and a handy way to see how Ivy maps Maven scopes onto configurations. The POM:

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>io.tidepool</groupId>
  <artifactId>tidepool-engine</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-csv</artifactId>
      <version>1.14.1</version>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.11.4</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
<ivy:convertpom pomFile="pom.xml" ivyFile="build/ivy-from-pom.xml"/>
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven">
	<info organisation="io.tidepool"
		module="tidepool-engine"
		revision="1.0.0"
		status="release"
		publication="20261016120201"
	>
		<description homepage="" />
	</info>
	<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="public" 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>
	<publications>
		<artifact name="tidepool-engine" type="jar" ext="jar" conf="master"/>
	</publications>
	<dependencies>
		<dependency org="org.apache.commons" name="commons-csv" rev="1.14.1" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>
		<dependency org="org.junit.jupiter" name="junit-jupiter-api" rev="5.11.4" force="true" conf="test->runtime(*),master(*)"/>
	</dependencies>
</ivy-module>

This is the mapping that every Maven module gets when Ivy reads its POM: the ten fixed configurations (default, master, the scopes compile, provided, runtime, test, system, plus sources, javadoc and optional), a master configuration for the module’s own artifact, dependencies mapped scope to scope, and force="true" on every dependency (Maven’s "the version in the POM wins" in Ivy’s vocabulary). It also explains the inline-resolve surprise earlier: asking for a Maven module without saying which of these configurations you want gives you all of them. The publication attribute is the time of the conversion. Going the other way (Ivy descriptor to POM) is makepom, on Ivy: Publishing & Multi-Project Builds.

Source: Ivy: convertpom

Task reference

Task Purpose Page section

settings, configure

Load ivysettings.xml into an Ivy instance (lazily, immediately).

Settings

var

Set an Ivy variable.

Variables and the cache

resolve

Resolve a descriptor or one module and fill the cache.

resolve

retrieve

Copy resolved artifacts into the project, optionally synchronising.

Post-resolve tasks

cachepath, cachefileset

Ant path or fileset over the cache.

Post-resolve tasks

artifactproperty, artifactreport

Properties or an XML list describing the artifacts.

Post-resolve tasks

report, repreport

HTML, XML, GraphML and DOT reports of a resolve or a repository.

Looking at the result

dependencytree, checkdepsupdate

Console tree and available updates.

Looking at the result

info, findrevision, buildnumber, listmodules

Query a descriptor or a repository without resolving.

Asking questions without resolving

cleancache

Empty a cache.

Variables and the cache

install

Copy a module and its dependencies from one resolver to another.

Moving modules between repositories

convertpom

Turn a pom.xml into an ivy.xml.

Moving modules between repositories

deliver, publish, makepom, buildlist

Produce a releasable descriptor, publish a module, write a POM, order modules.

Ivy: Publishing & Multi-Project Builds

The same jobs in the other tools

Job Ivy Maven Resolver Ant Tasks Maven

Declare dependencies

ivy.xml or nested dependency

nested dependencies or a POM

pom.xml

Resolve and use as a path

cachepath

resolve with path

plugin class paths

Copy to a directory

retrieve

resolve with files and copy

dependency:copy-dependencies

Newer versions

checkdepsupdate

-

versions:display-dependency-updates

Copy between repositories

install

-

dependency:copy, a repository manager

The task library that follows the Maven model, without configurations, is on Maven Resolver Ant Tasks. The shared theory of coordinates, scopes and conflicts is on Dependency Management Fundamentals.

Where older material is outdated

  • Ivy’s own documentation and older books show <ivy:retrieve/> writing to lib/[artifact]-[revision].[ext]; in 2.6.0 the default pattern is ${ivy.lib.dir}/[artifact]-[revision](-[classifier]).[ext].

  • Many tutorials put ivy-2.2.0.jar or ivy-2.5.x.jar in a lib directory, or download a pinned old version at the start of the build; for the current release see the overview page, and mind that 2.6.0 contains security fixes.

  • Examples that resolve from "ivyrep" or from Bintray point to services that have been shut down. Use Maven Central with an ibiblio resolver and m2compatible="true", as in this page.

  • symlinkmass on retrieve is deprecated since 2.5 and does nothing.

  • <ivy:cachepath pathid="x" inline="true" .../> is the modern replacement for the old <ivy:resolve ... pathid=.../> idiom that some blog posts show; resolve has no pathid.

Common problems

  • Nothing is resolved but the build says success: check log; quiet and download-only print nothing when all is cached. Print ${ivy.resolved.configurations} or use dependencytree.

  • unknown resolver ... in the problems summary: seen when two settings files with different resolver names shared one cache directory (a resolve that used the second file reported the first file’s resolver name as unknown). It disappeared when each settings file got its own cache directory.

  • retrieve removed my files: sync="true" owns its root directory; see above.

  • Properties such as ivy.revision do not change: Ant properties are immutable; the Ivy tasks that set them overwrite, but your own property of the same name wins if defined first.

  • Parallel builds fail with "module not found" for something that exists: the concurrency rule of resolve.

References