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-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>
<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):
<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:
-
Settings load an
ivysettings.xml(settings,configure) or set Ivy variables (var). -
resolvereads anivy.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).reportrenders 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.
Source: Ivy: Ant tasks, first steps
Source: Ivy: Ant tasks, the usual cycle
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 |
|---|---|
|
A declaration. The file is loaded the first time some task needs it, so a typo is reported later, at that task. |
|
Loads the file immediately, so a problem is reported at the line that caused it. The |
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:
<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 |
|---|---|
|
Descriptor to resolve and the comma-separated configurations to resolve. |
|
|
|
|
|
|
|
Comma-separated artifact types to accept; the default comes from |
|
Whether an unresolved dependency fails the build (default |
|
|
|
|
|
Force or skip validation of |
|
A name that later tasks use to refer to this resolution. The default is |
|
Compute |
|
Keep the result in memory for the post-resolve tasks. Default |
|
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
Source: Ivy: resolve, attributes
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.
Source: Ivy: resolve, inline mode and Ivy: cachepath
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.
Source: Ivy: resolve, child elements
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.
Source: Ivy: resolve, attributes
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
Source: Ivy: resolve, inline mode
Source: Ivy: resolve, resolve mode
Source: Ivy: resolve, concurrency
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.
Source: Ivy: post-resolve tasks
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 |
|---|---|
|
Where files go; the default is |
|
Retrieve only these configurations and artifact types (all by default). |
|
Delete everything under the pattern’s root directory that the retrieve did not just place there. Default |
|
|
|
Create symbolic links instead of copies, falling back to a copy when the file system refuses. (The older |
|
Also copy the descriptors of the dependencies, using this pattern. |
|
Create an Ant path or fileset of the retrieved files (since 2.3). |
|
|
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
Source: Ivy: retrieve, examples
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
Source: Ivy: cachefileset
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.
Source: Ivy: artifactproperty
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>
Source: Ivy: artifactproperty
Source: Ivy: artifactreport
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 |
|---|---|
|
Output directory (default |
|
Configurations to report on; by default those of the last resolve. |
|
Generate the report with XSLT (default |
|
Also keep the raw XML (default |
|
GraphML files (default |
|
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, withrev-constraint-defaultandrev-constraint-dynamicfor 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.
Source: Ivy: dependencytree
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.
Source: Ivy: checkdepsupdate
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.
Source: Ivy: findrevision
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.
Source: Ivy: buildnumber
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.
Source: Ivy: listmodules
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-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>
<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>
<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:
<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 |
|---|---|---|
|
Load |
Settings |
|
Set an Ivy variable. |
Variables and the cache |
|
Resolve a descriptor or one module and fill the cache. |
|
|
Copy resolved artifacts into the project, optionally synchronising. |
Post-resolve tasks |
|
Ant path or fileset over the cache. |
Post-resolve tasks |
|
Properties or an XML list describing the artifacts. |
Post-resolve tasks |
|
HTML, XML, GraphML and DOT reports of a resolve or a repository. |
Looking at the result |
|
Console tree and available updates. |
Looking at the result |
|
Query a descriptor or a repository without resolving. |
Asking questions without resolving |
|
Empty a cache. |
Variables and the cache |
|
Copy a module and its dependencies from one resolver to another. |
Moving modules between repositories |
|
Turn a |
Moving modules between repositories |
|
Produce a releasable descriptor, publish a module, write a POM, order modules. |
The same jobs in the other tools
| Job | Ivy | Maven Resolver Ant Tasks | Maven |
|---|---|---|---|
Declare dependencies |
|
nested |
|
Resolve and use as a path |
|
|
plugin class paths |
Copy to a directory |
|
|
|
Newer versions |
|
- |
|
Copy between repositories |
|
- |
|
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 tolib/[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.jarorivy-2.5.x.jarin alibdirectory, 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
ibiblioresolver andm2compatible="true", as in this page. -
symlinkmassonretrieveis 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;resolvehas nopathid.
Common problems
-
Nothing is resolved but the build says success: check
log;quietanddownload-onlyprint nothing when all is cached. Print${ivy.resolved.configurations}or usedependencytree. -
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. -
retrieveremoved my files:sync="true"owns its root directory; see above. -
Properties such as
ivy.revisiondo not change: Ant properties are immutable; the Ivy tasks that set them overwrite, but your ownpropertyof the same name wins if defined first. -
Parallel builds fail with "module not found" for something that exists: the concurrency rule of
resolve.
References
-
Apache Ivy documentation: Ant tasks
-
Apache Ivy documentation: settings
-
Apache Ivy documentation: configure
-
Apache Ivy documentation: resolve
-
Apache Ivy documentation: post-resolve tasks
-
Apache Ivy documentation: retrieve
-
Apache Ivy documentation: cachepath
-
Apache Ivy documentation: cachefileset
-
Apache Ivy documentation: artifactproperty
-
Apache Ivy documentation: artifactreport
-
Apache Ivy documentation: report
-
Apache Ivy documentation: repreport
-
Apache Ivy documentation: dependencytree
-
Apache Ivy documentation: checkdepsupdate
-
Apache Ivy documentation: info
-
Apache Ivy documentation: findrevision
-
Apache Ivy documentation: buildnumber
-
Apache Ivy documentation: listmodules
-
Apache Ivy documentation: var
-
Apache Ivy documentation: cleancache
-
Apache Ivy documentation: install
-
Apache Ivy documentation: convertpom