Introduction to Apache Ivy

Introduction to Apache Ivy

Apache Ivy is a multifaceted tool dedicated to composing dependencies with a very high degree of flexibility - not only for the Java ecosystem.

We are now sailing on a brief tour of Ivy, trying to grasp its very essence - with no claim of completeness.

Actually, Ivy is a huge field full of details, so we can now describe just the tip of the iceberg; that should be enough to understand the overall picture and navigate its comprehensive documentation.


Gianluca Costa

August 18, 2018


  1. Gianluca Costa Introduction to Apache Ivy Based on Ivy 2.5

    Latest update: 2018-08-18
  2. Foreword Elegance always matters, especially when creating vast and complex

    software architectures - and modularity is a core value of supple design Apache Ivy is a multifaceted tool dedicated to composing dependencies with a very high degree of exibility - not only for the Java ecosystem This work was inspired by my passion for build automation - for example, I created Aurora, my own build solution - as well as by valuable tech-themed coffee breaks with Marco Marani - especially on cache isolation, latest strategies and Maven compatibility 2
  3. About this presentation We are now sailing on a brief

    tour of Ivy, trying to grasp its very essence - with no claim of completeness. Actually, Ivy is a huge eld full of details, so we can now describe just the tip of the iceberg; that should be enough to understand the overall picture and navigate its comprehensive documentation. Please keep in mind that there's often at least one way to alter the default behavior we are going to explore - so always consult the of cial reference for details! ^__^ 3
  4. Section 1 Introduction

  5. What is Ivy? Ivy is an open-source dependency manager It

    is written in Java and can run standalone, but it's even better when integrated in Apache Ant For Java projects, a basic scenario consists in: copying dependencies to a lib project directory - required by Java compiling, testing, ... publishing the project artifacts to a repository 5
  6. Main features Extreme exibility: Ivy's most stunning aspect is probably

    its wide variety of hook points Declarative syntax for modules and settings Compatibility with Maven Transitive dependencies and con ict management Reports in different formats (HTML, graphs, ...) Ready for Continuous Integration and its artifacts High performances - if you con gure it well! 6
  7. Section 2 Conceptual bricks

  8. Simpli ed overview 8

  9. Part 2.1 Modules

  10. Module elements Module: self-contained, reusable software unit Descriptor: identi es

    the module and its artifacts Artifact: single le to be delivered as part of the module In Java, JAR archives are a standard Other compressed formats (such as zip) are anyway convenient Every module can include zero or more artifacts 10
  11. Module descriptor Can have different formats: Ivy's ivy.xml le Maven's

    .pom le Even custom descriptors can be read, via dedicated Ivy plugins Attributes: uniquely identify the module, actually enabling Ivy to correctly resolve it 11
  12. Ivy's descriptor attributes Organisation: identi es the producer - usually,

    via its inverted DNS name Module name: the name of the module itself Revision: unique identi er of a delivered module version - be it a release or just a CI publication Branch: the branch, in the version-control system, whose code generated the module (optional) Status: the stability of the module (optional) Publication: the publication timestamp - in yyyyMMddHHmmss format (optional) 12
  13. Module status To describe the stability of a module, Ivy

    provides, by default, 3 categories: integration: the less stable - usually a nightly build (default) milestone: an un nished yet working module release: the most stable and tested publication type Additional statuses can be plugged into Ivy, if required 13
  14. Module artifact attributes Name: lename, without extension Extension: lename extension

    (without dot); implies the format of the artifact - how it should be used. For example, jar, zip, png, jpg, txt ... Type: de nes the purpose of the artifact - why it should be used, e.g. binary and source code. For example, you could have 2 artifacts whose type is source code: the former as .jar, the latter as a .zip Packaging: implies post-resolution operations, such as extracting a directory from a zip artifact 14
  15. Part 2.2 Con gurations and dependencies

  16. Module con gurations Con guration = a way to use

    or construct a module In other terms, a con guration de nes the structure of the module in a speci c scenario: The dependencies required to build the module The artifacts published by the module A library might have different requirements according to whether it is in a CLI app or in a Java EE container If you do not declare any con guration, a public one named default is automatically created 16
  17. Con guration attributes A module can declare one or more

    con gurations (also said conf's), each having these attributes: name - mandatory and unique within the module visibility: by default it is public; a private conf cannot be referenced by other modules description: the conf's description (optional) transitive: if true (the default), the conf becomes part of a chain of transitive dependencies deprecated: if the conf might be removed soon 17
  18. Module dependencies A dependency is always declared as a reference

    to a module However, Ivy actually handles dependencies in terms of con guration mapping, which expresses how con gurations in the current module depend on public con gurations in the dependency Consequently, dependencies are not on artifacts, but on con gurations - which in turn provide a set of artifacts 18
  19. Con guration mapping The notation used by Ivy is A->B

    - where: A is a con guration in the current module and is called master conf B is a con guration in the dependency module and is called dependency conf Both sides admit a *, meaning all con gurations. Both sides also admit a comma-separated list of confs: for example, A,B->C equates to A->C and B->C 19
  20. Composite mappings In a mapping, you can explicitly declare multiple

    mappings separated by semicolons, for example: X->Y; A->A,B; Z->* X in this module depends on Y in the other A in this module depends on A and B in the other Z in this module depends on all confs of the other You can also make all con gurations require a speci c con guration in a dependency: * -> X 20
  21. Special mappings *->@ means every conf maps only to the

    dependency conf having the same name - unlike *->*, which maps any to any % is only on the left side of -> and means all the other master con gurations not mapped until now. For example, in A->X; B->Y; %->Z, A gets X, B gets Y and all the other con gurations reference Z A->B(X): A references B, but if B is not available, reference X instead 21
  22. Further mappings Con guration mappings can be even more sophisticated:

    please, refer to Ivy's documentation for more details: rc1/ivy le/dependency.html 22
  23. Part 2.3 Versioning

  24. Versions and dependencies In Ivy, the version of a module

    is denoted by the revision attribute in its descriptor. When declaring a dependency on another module, you must also state the version you require, which can be: a xed version - such as 1.5.2 a dynamic version - that is, a string that will be determined during the resolution phase, according to the modules available when running Ivy 24
  25. Dynamic versioning latest.STATUS: selects the latest version of the module

    having the given STATUS - which can be one of the 3 default ones, or even a plugged one + notation: selects the latest version for just part of the revision. For example, if 2.1.3, 2.6.7, 2.6.8, 2.9 and 3.0 are available for a module, 2.6.+ will choose 2.6.8. Mathematical range: in the example above, both [2.0, 3.0[ and [2.0, 3.0) select the latest version that is both >=2.0 and <3.0 - that is, 2.9 25
  26. Version con icts There are situations where Ivy nds multiple

    candidate versions of the same module - especially when navigating a complex dependency tree Ivy introduces con ict managers to lter such a set of con icting versions - most often, they select just one revision - somehow identi ed as the latest version You can also apply different con ict managers - even custom ones - to different modules Con ict managers try to be eager, evicting artifacts as soon as possible during the resolution process 26
  27. Ivy's con ict managers latest-revision: selects the latest by revision

    - using a string comparison of revisions. (default) latest-time: selects the latest in time latest-compatible: selects the latest version also having a compatible set of dependencies all: just performs no ltering strict: stops the process with an error You can also de ne custom con ict managers, even via XML, especially ones based on a custom latest strategy 27
  28. Latest version Ivy expects that we want the latest version

    in a range of situations - for example, in custom con ict managers To exactly de ne the latest version of a module, Ivy includes 3 default latest strategies - and even supports custom ones 28
  29. Built-in latest strategies latest-revision: simple and ef cient, compares version

    components as expected in software development. In particular, Ivy's documentation mentions similarities with PHP's version_compare() latest-time: compares the revision timestamps. Conceptually simple, its drawback consists in the fact that retrieving such timestamps from remote sources can be quite a costly operation latest-lexico: compares revisions using Java's lexicographic order for strings 29
  30. Circular dependencies The simplest circular dependency consists in a module

    A depending on a module B, which in turn depends on module A. Ivy has 3 different built-in policies to handle circular dependencies: warn: prints out a warning (default) ignore: just prints out a verbose-level message error: halts the resolution process 30
  31. Part 2.4 Repositories and resolvers

  32. Repositories Repository = distribution location providing modules. Also mentioned as

    repo Repositories can differ in a wide range of parameters: Location: local, remote Access protocol: le system, HTTPS, SSH, VFS, ... Descriptor format: Maven, Ivy, custom, ... Layout: how les are archived within the repo Dependency resolvers are Ivy's solution to the problem 32
  33. Dependency resolvers Dependency resolver = pluggable Java class designed to

    access a repository in order to: Retrieve a module descriptor Retrieve the module's artifacts and, optionally, its transitive dependencies Publish module les - acting as a two-way channel From now on, we'll use resolver as shorthand for dependency resolver 33
  34. Kinds of resolvers Resolvers can be divided into 2 main

    categories: Standard resolvers: provide concrete access to a repository. Examples: lesystem, url Composite resolvers: combine other resolvers in the context of a custom algorithm Examples: chain (which is extremely important), dual 34
  35. Classes in Ivy con guration Resolvers are Java classes -

    however, it would not be practical to always mention them via their fully- quali ed class name (FQN) Instead, and as a general rule, Ivy provides XML tags - one per built-in resolver (we have just seen chain) Therefore, the attributes of each tag are mapped to properties of the related resolver instance We'll see that such an elegant mechanism is available for custom classes, too 35
  36. Standard resolvers Standard resolvers encapsulate 2 distinct use cases: the

    access protocol to a repository the logic to locate descriptors and artifacts within it (the repository's layout) Both aspects are to be set up in order to successfully access any repository. Consequently, con guring a standard resolver can be thought of as a way to empirically describe a repository 36
  37. Main standard resolvers bintray: Bintray repository, including JCenter ibiblio: ibiblio

    repository, including Maven Central url: very general way to access a repo via its URL lesystem: repository on the local lesystem ssh: repository accessible via SSH vfs: repo accessible via Apache Virtual File System sftp: repository hosted via SFTP jar: the whole repository is compressed as a JAR le 37
  38. Locating les within a repo Now that we have seen

    that a standard resolver can access a repo, how does it locate a module's les (i.e., descriptor and artifacts)? Ivy's solution lies in patterns: Pattern = string denoting the path of a module's le. It includes special placeholders named pattern tokens. Every standard resolver has: patterns to locate the module descriptor (0 or more) patterns to locate artifacts (at least one) 38
  39. Pattern tokens Pattern tokens are placeholders that are replaced by

    Ivy whenever it must locate a module's le - by injecting the Ivy coordinates of the requested le: Information set Pattern tokens Basic module info [organisation], [module], [revision] Additional info [branch], [orgPath], [conf] Artifact [artifact], [type], [ext], [originalname] 39
  40. Pattern example This could be a reasonable pattern to organize

    the artifacts within a repo: [organisation]/[module]/[revision]/[artifact]- [revision].[ext] Such a pattern would resolve, for example, into: info.gianlucacosta/aurora/9.0/aurora-9.0.jar Of course, the pattern must re ect the actual internal structure of the repository - or les won't be found 40
  41. Pattern tokens and variables Ivy supports variables - which are

    very similar to Ant properties - with a few differences such as the fact that Ivy variables can be overridden. Pattern tokens are similar to variables, but tokens are placeholders systematically replaced by Ivy with module and artifact coordinates, whereas variables exist on their own and usually have a longer lifespan - for example, they can be de ned in con guration les. It is interesting to note that a pattern can also include variables - in addition to pattern tokens, of course 41
  42. Conditional groups in a pattern Conditional group: substring, in a

    pattern, delimited by parentheses and containing exactly one pattern token If the pattern token has a non-null, non-empty injected value, the token is replaced and the whole group appears as it is, without parentheses Otherwise, the whole group is omitted from the pattern A useful example is [artifact](-[revision]).[ext]: if revision is missing, the hyphen will be omitted as well 42
  43. Pattern generality Patterns apply to a wide variety of contexts

    - not only repository access via resolvers. Wherever a pattern is requested, you can apply all the related features - such as pattern tokens and conditional groups. For example, we'll soon study the pattern attribute of the ivy:retrieve Ant task 43
  44. Module descriptors and artifacts Technically speaking, module descriptors should not

    be classi ed as artifacts. However, you will often nd Ivy patterns for module descriptors that actually include the tokens dedicated to artifacts - especially [artifact], [type] and [ext], which work for module descriptors as well Similarly, Ant tasks such as artifacts in ivy:publish can also be used to locate the descriptor in the project dir 44
  45. Composite resolvers Composite resolvers are not focused on directly retrieving

    les; instead, they orchestrate other resolvers (that can even be nested composite resolvers) according to a speci c algorithm. The most important composite resolvers are: Dual resolver: to decouple descriptor repo and artifact repo, especially when the latter is legacy Chain resolver: one of the most important Ivy resolvers, as it implements the concept of fallback strategy in the form of a chain of resolvers 45
  46. Dual resolver Composite resolver that decouples module descriptor retrieval from

    artifact retrieval Consequently, module descriptors can reside in a repository and artifacts can reside in another - which is very useful when dealing with legacy artifacts It is con gured by providing 2 sub-retrievers: the former performs module descriptor resolution the latter performs artifact resolution 46
  47. Chain resolver Composite resolver con gurable to sequentially look for

    modules within multiple repositories via the resolvers associated with it Actually applies the chain of responsibility pattern By default, it scans all of its repositories - useful if you are looking for the latest revision of a module - but you can also ne-tune it to return just the rst hit It can also be con gured as a dual chain: that is, the chain is queried once to fetch the descriptor and then again to separately fetch the artifacts 47
  48. Retrieving the latest version Resolvers such as the chain resolver

    highlight the importance of the latest version concept for any Ivy dependency - both statically and dynamically versioned It is important to notice that your resolver might skip or limit the process of latest version selection - for example, we have seen that the chain resolver can return just the rst hit in lieu of querying its whole chain. If your latest strategy does not work as expected, please check both the con guration and the documentation of your resolvers 48
  49. Forcing a resolver Every standard resolver has a force property

    that, when set to true, has a twofold effect: always looks for latest.integration, no matter what the requested revision actually is immediately return a matching dependency - even if used in a chain resolver not returning the rst hit This property can be especially useful on a resolver targeting one's local repository, so as to always get the latest version and skip queries on remote repos 49
  50. Further details on resolvers Resolvers are a very exible area

    in Ivy's architecture: apart from the shared traits we have seen, every resolver has speci c properties To learn more details about resolvers, please refer to: rc1/settings/resolvers.html In particular, every resolver has a dedicated page, accessible from the navigation sidebar 50
  51. Part 2.5 Combining repositories

  52. Default repositories Ivy comes with sensible, exible default repository con

    guration, designed for enterprise developers working in a team You can keep this structure and con gure it - by setting the variables affecting it... ...but you can also design a brand-new set of repositories, tailored to your needs! 52
  53. Default repositories - schema 53

  54. Local repository The local repository is the developer's own repository

    If a dependency is found in it, the other repos are not accessed 54
  55. Con guring local repository Directory: ivy.local.default.root= "${ivy.default.ivy.user.dir}/local" Descriptor pattern: ivy.local.default.ivy.pattern=

    "[organisation]/[module]/[revision]/[type]s/[artifact]. [ext]" Artifact pattern: ivy.local.default.artifact.pattern= "[organisation]/[module]/[revision]/[type]s/[artifact]. [ext]" 55
  56. Shared repository The shared repository should be owned by the

    whole team It is accessed via lesystem, so it should reference a mount point - targeting, for example, network storage 56
  57. Con guring shared repository Directory: ivy.shared.default.root= "${ivy.default.ivy.user.dir}/shared" Descriptor pattern: ivy.shared.default.ivy.pattern=

    "[organisation]/[module]/[revision]/[type]s/[artifact]. [ext]" Artifact pattern: ivy.shared.default.artifact.pattern= "[organisation]/[module]/[revision]/[type]s/[artifact]. [ext]" 57
  58. Public repository The public repository is Maven Central, which is

    quite a common repository in the Java ecosystem. Of course, you might want to replace it with another repository, such as Bintray's JCenter, using the dedicated bintray resolver. 58
  59. Part 2.6 Caching

  60. Caching in Ivy Resolvers access repositories - but that might

    actually involve expensive operations - such as accessing a remote site Therefore, Ivy introduces caching - which is not to be mistaken for the local repository! Ivy has 2 levels of caching: resolution caching: internally used by Ivy and overwritten when a new resolution process starts repository caching: stores the actual repository les and related metainfo 60
  61. Cache details Ivy has a built-in cache, by default referenced

    by all resolvers and which is the only cache that can perform resolution caching - to a resolutionCacheDir. It also performs repository caching to the repositoryCacheDir. You can de ne additional repository caches, each having a base directory (basedir). As already mentioned, such a directory must not be a repository - not even a local one! Every resolver points to one repository cache, which the resolver queries even before its own repository 61
  62. Cache isolation Ivy's built-in caches are NOT thread-safe Again: Ivy's

    built-in caches are NOT thread-safe In the case of resolutionCacheDir: different Ivy processes running in parallel MUST point to different resolutionCacheDir directories In the case of repositoryCacheDir of the built-in cache, as well as for custom caches' basedir, you can enable concurrent access support by setting the cache's lockStrategy property to artifact-lock-nio 62
  63. Change management By default, Ivy assumes that a module revision,

    once created, never changes - which makes caching simple! However, in practice, the assumption might be false: how to invalidate Ivy's cache in such cases? There are 2 distinct situations: Descriptor changes: patched metainfo, patched dependency declarations, ... Artifact changes: the most common example is the SNAPSHOT version in Maven and Gradle - designed to invalidate caching by de nition 63
  64. Descriptor changes First of all, you should set the checkmodi

    ed property of your resolvers to true. This algorithm then applies: 1. If the last modi ed timestamp for the descriptor, as returned by the repository, is not more recent than the one in the cache, still use the cached version 2. Otherwise, update the cache - and use the new version 64
  65. Artifact changes To support cache invalidation for artifacts, you must

    introduce the concept of changing dependency Set the changing property of the dependency to true, if you want to check just a speci c dependency Set the changingPattern and changingMatcher properties of your resolvers, if you want a generalized handling That does not end here - because Ivy applies a dedicated algorithm before invalidating a changing dependency 65
  66. Changing dependencies The algorithm applied by Ivy is: 1. If

    the module metadata hasn't changed, still use the cache; this does not mean that you must always update it manually, as Ivy enriches the descriptor on publishing - e.g., setting the publication attribute - if missing - to the current build timestamp 2. If the module descriptor's publication attribute is not more recent than the cached one, still use the cache 3. Finally, update the cached artifacts, after checking each of them on a last-modi ed timestamp basis 66
  67. Section 3 Ivy in practice

  68. Part 3.1 Plugging Ivy into Ant

  69. Ivy and Ant Ivy is a natural companion to Apache

    Ant In particular, it provides a set of Ant tasks that vastly simplify the process of: con guring Ivy retrieving dependencies publishing modules 69
  70. Installing Ivy for Ant 1. Download the binary zip from

    Ivy's download page; for the most common scenarios, the zip without additional dependencies will suf ce 2. Copy Ivy's jar le to one of these directories: $HOME/.ant/lib - per-user installation $ANT_HOME/lib - global installation 3. Should you ever need to install the additional dependencies, please refer to Ivy's documentation 70
  71. Ant project + Ivy The most common steps are: 1.

    Import the Ivy task library 2. Create a descriptor for the project - which now becomes a module. The default name is ivy.xml 3. Con gure Ivy, by reading its settings from an XML le - conventionally named ivysettings.xml 4. Retrieve the dependencies - that is, copy them to the lesystem - in our case, to a project subdirectory 5. Finally, mainly if the project is a library, publish it 71
  72. Basic Ant build le with Ivy <project name="TestLib" xmlns:ivy="antlib:org.apache.ivy.ant"> <!--

    The settings file to configure Ivy: omit the tag if you create ivysettings.xml in the project's basedir or if you want to use Ivy's default settings --> <ivy:settings file="ivysettings.xml" /> <!-- The module descriptor; omit if you have ivy.xml in the project directory --> <ivy:info file="ivy.xml" /> </project> 72
  73. Retrieving dependencies You need the ivy:retrieve Ant task, to which

    you should pass a pattern telling Ivy where the artifacts should be stored. The pattern usually points to a directory relative to the project's basedir - for example, lib <target name="getDependencies"> <!-- Copy dependencies to "lib" subdirectories, one for each Ivy module configuration --> <ivy:retrieve pattern="lib/[conf]/[artifact](-[revision])(.[ext])" /> </target> 73
  74. Retrieving and resolving Retrieving dependencies also automatically performs a few

    important actions: 1. Reading Ivy settings 2. Resolving dependencies - that is, ensuring they are in Ivy's cache system - which might also require accessing repositories via resolvers 74
  75. Running Ant to get dependencies Given the example in the

    previous pages, and once the module descriptor is in place in the project directory, to retrieve all the dependencies one should just run: ant getDependencies to populate the lib dir and its subdirectories - where each subdirectory contains the dependencies of a speci c con guration 75
  76. Part 3.2 Ivy descriptor

  77. Introduction Ivy's module descriptor is a simple XML le declaratively

    stating several aspects of the module. By default, the descriptor is called ivy.xml and resides in the project directory - in this case making the ivy:info task super uous. We are going to see just the main points; for further details, please refer to the related documentation 77
  78. Minimal descriptor <ivy-module version="2.0"> <info organisation="info.gianlucacosta" module="test-library" revision="1.5" /> </ivy-module>

    Additional interesting information can be added: Other descriptor attributes, such as status and publication - but you can let Ivy add them Description, author details and license 78
  79. Basic dependencies Basic dependency declaration is very similar to Maven

    - via the dependencies and dependency tag. As an example, to depend on a speci c version of our library: <ivy-module version="2.0"> ... <dependencies> <dependency org="info.gianlucacosta" name="test-library" rev="1.5" /> </dependencies> </ivy-module> 79
  80. Declaring con gurations In Ivy, you use the con gurations

    tag: you nest con guration tags within it its defaultconf attribute declares the con guration a dependency belongs to, if such dependency has no con guration explicitly declared its defaultconfmapping de nes the default con guration mapping, without bypassing defaultconf Actually, defaultconf and defaultconfmapping can equivalently belong to the dependencies tag 80
  81. Dependencies & con gurations The dependency tag has a conf

    attribute, which is optional and whose value can be: a con guration name a con guration mapping - even a composite one As we have seen, Ivy always works in terms of con guration mappings when resolving dependencies 81
  82. Dependency conf mappings 82

  83. Con guration inheritance When a con guration extends one or

    more con gurations - via the extends attribute of the con guration tag - it automatically inherits all the dependency artifacts of the extended con gurations. For more details: rc1/ivy le/conf.html 83
  84. Part 3.3 Publishing with Ivy

  85. Resolvers as two-way channels We have used resolvers to resolve

    dependencies, fetching them from repositories However, Ivy expects that resolvers are two-way channels, actually able to write les into repositories Please, refer to the documentation of your speci c resolvers to ensure this assumption is true for all your resolvers 85
  86. Publishing overview 1. Properly write ivy.xml - the module descriptor

    - declaring what your artifacts are 2. Con gure one resolver per target repository, using ivysettings.xml - although even the default con guration is ne (e.g.: the local resolver) 3. In Ant's build.xml: 1. call ivy:resolve - or a post-resolve task such as ivy:retrieve - at least once in the build 2. call the ivy:publish task for each repo, declaring the paths where the artifacts can be found 86
  87. Declaring artifacts To declare artifacts, you need the publications block:

    It lies before the dependencies block It includes zero or more artifact tags If you omit publications, one module-related jar is assumed as artifact, whereas an empty publications tag means no artifacts, publish just the descriptor <publications> <artifact name="myLib" type="jar" conf="compile" /> <artifact name="README" ext="md" type="text" conf="src" /> </publications> 87
  88. Artifacts and con gurations Every artifact is always produced by

    one ore more con gurations: The artifact tag supports a conf attribute, accepting a comma-separated list of con gurations that produce it - making it available to other modules that depend on one of such con gurations The publications tag supports a defaultconf that is applied to any artifact tag missing the conf attribute. The default value is *, meaning all con gurations 88
  89. The artifact tag In addition to conf, artifact supports attributes

    to set all of the properties we have already seen: name: defaults to the module's name type: defaults to jar ext: defaults to the value of type Additionally, it provides a url attribute to declare a fallback URL in case of missing artifact in the resolution process 89
  90. Declaring the resolvers You must declare one or more resolver

    tags in your ivysettings.xml le, within the resolvers container tag. In the context of this example, we'll skip creating ivysettings.xml in the project directory, so that Ivy falls back to the default repositories - among which we'll be using local 90
  91. Con guring Ant's ivy:publish In build.xml, the ivy:publish task has

    3 paramount attributes: resolver: the name of the resolver used to publish. To publish to multiple repos, declare multiple ivy:publish overwrite: if set to true, overwrites existing les in the repo (default: false) publishivy: if set to true (the default), publishes the ivy.xml descriptor as well Its main subtag is artifacts - that we're going to see 91
  92. The artifacts tag Ivy does not create artifacts - you

    must create them via your custom Ant build process Therefore, you must tell ivy:publish where the artifacts reside: to do so, you need one or more artifacts subtags - each for a possible artifact source (usually a subdir of a build or dist project directory) artifacts takes a pattern attribute, to match one or more artifact les in the project; pattern tokens - especially [name], [ext] and [type] - should be used. An example is in the next page 92
  93. Artifact patterns - example <ivy:publish resolver="local" overwrite="true"> <artifacts pattern="dist/a/[artifact].[ext]" />

    <artifacts pattern="dist/b/[artifact].[ext]" /> </ivy:publish> The 2 artifacts tags state that artifacts can equivalently be taken from either dist/a or dist/b For each artifact, the patterns are applied in declaration order For each pattern, pattern tokens are replaced The rst pattern matching a le registers such le as the source of the current artifact 93
  94. Artifact lename transforms Consider this line in Ant's build.xml for

    a project named TestLib - even if the module name in ivy.xml is test-lib: <artifacts pattern="dist/${}.[ext]" /> In this case, every published artifact declared in ivy.xml will be looked for in dist/TestLib.[ext]; for example: <artifact type="pom" /> in ivy.xml will try to look for dist/TestLib.pom: it would be the source of the test-lib.pom artifact - which could later have even another lename in the repo 94
  95. Artifacts and le names 95

  96. The rst artifacts tag When you let Ivy publish the

    Ivy descriptor, it usually seems good to de ne the rst artifacts tag as follows: <ivy:publish> <artifacts pattern="dist/[artifact].[ext]" /> ... </ivy:publish> where dist is a directory, in the project tree, dedicated to receiving output artifacts. It can have any name. Ivy will store into this dir the enriched ivy.xml - having for example, a publication attribute stating the current build timestamp 96
  97. Descriptor inheritance A module descriptor can inherit one or all

    sections from a published module descriptor. This can be achieved via the extends tag, under the info block in Ivy's descriptor. For example, to extend our sample module: <info organisation="com.example" module="..." revision="..." /> <extends organisation="info.gianlucacosta" module="test-library" revision="1.5" /> </info> 97
  98. Documentation for ivy.xml ivy.xml lets you de ne several aspects

    of your module; for the full documentation please refer to: le.html 98
  99. Part 3.4 Ivy settings

  100. Ivy con guration les Ivy is con gured via an

    XML le whose name is conventionally ivysettings.xml; it is an extremely vast topic - the very core of Ivy's exibility. The settings le contains Ivy's low-level, general con guration - which is therefore decoupled from the speci c module con guration - which in turn is provided by ivy.xml. Last but not least, Ivy can also be con gured by assigning values to speci c Ivy variables 100
  101. Basic ivysettings.xml <ivysettings> <!-- Repeat this tag to include one

    or more existing, well-formed, even if small configuration files --> <include ... /> <!-- CONFIGURATION TAGS --> </ivysettings> The include tag is great to include an existing, well- formed con guration le from the lesystem or a URL; every inclusion can also be marked as optional - causing no errors in case of missing le 101
  102. Locating ivysettings.xml When calling Ivy from Ant: If you create

    ivysettings.xml in the project's build dir, it will be used in lieu of the default one If you use the ivy:con gure or ivy:settings Ant tasks, you can provide a le path or a URL - for example ${user.home}/ivysettings.xml - and will be used instead of the default one. It can have any lename Otherwise, Ivy's default settings le will be used 102
  103. Referencing the default ivysettings.xml Whenever you employ a con guration

    le for Ivy, the default one is no more used. However, it has sensible defaults you might want to keep - such as the local, shared and public repositories. To reference the default con guration, you should employ the following include in your ivysettings.xml: <include url="${ivy.default.settings.dir}/ivysettings.xml"/> 103
  104. Con guring resolvers Resolvers can be de ned by adding

    sub-elements to the resolvers tag and by setting properties via tag attributes; for example: <resolvers> <!-- Resolver with name (mandatory) and a property --> <filesystem name="local-m2" m2compatible="true"> <!-- You should add tokens to the pattern - such as [organization], [orgPath], [module], [revision], [artifact], [ext] and [type] --> <artifact pattern="${user.home}/.m2/repository/..."/> </filesystem> </resolvers> 104
  105. Descriptor and artifact patterns To declare repository patterns, you need

    two subtags available when con guring all standard resolvers: ivy, with its pattern attribute, to declare 0 or more module descriptor patterns. This tag is vital when accessing a Maven repository, as it must be used to correctly locate the POM le of a module (see later) artifact, with its pattern attribute, to declare at least one artifact pattern 105
  106. Using a resolver De ning a resolver is not enough:

    to use it during resolution, you have to to make it the default resolver*: <settings defaultResolver="myResolverName" /> Of course, if you want to use other resolvers as well - such as Ivy's default ones - you'll have to: 1. Add a chain to the con guration, containing both the new resolver and something else - such as one of the two default chains (default and main) 2. Set this new composite resolver as the default one 106
  107. Resolver names and typedef Resolvers can be used as tags

    - because each built-in resolver has a dedicated tag - like chain, dual, lesystem, ibiblio, ... This mechanism is general: in ivysettings.xml, you can use the typedef tag to map a Java fully-quali ed class name (FQN) to a tag This is especially useful if you de ne custom resolvers, but it can be useful in other contexts - such as custom caches, custom con ict managers, custom latest strategies 107
  108. Details on resolvers Resolvers are a universe, as they are

    one of Ivy's most valuable concepts. The general con guration details, as well as the per- resolver documentation, can be found at: rc1/settings/resolvers.html 108
  109. Con guring the cache system A wise con guration for

    caching, shareable between projects as a conf fragment (via include tag) could be: <ivy-settings> <caches resolutionCacheDir="${basedir}/.ivy-cache" repositoryCacheDir="${user.home}/.ivy2/repo-cache" lockStrategy="artifact-lock-nio" /> </ivy-settings> resolutionCacheDir is project-private, so no con icts occur when different projects are built in parallel repositoryCacheDir is shared to save space, but with a NIO-based locking strategy enforced 109
  110. Caching details The concepts already seen about caching in the

    previous sections actually map to the caches and cache tags. The related Ivy documentation can be found at: rc1/settings/caches.html 110
  111. Further ideas Here are a few con guration ideas that

    you could explore: macrodef de nes a custom resolver via XML, by composing and customizing existing ones signers con gures signature generators parsers supports the creation of custom module descriptor parsers namespaces are an advanced feature, especially useful when dealing with legacy software and different repository conventions 111
  112. Section 4 Maven compatibility

  113. Is Ivy compatible with Maven? The answer is: de nitely!

    ^__^ In particular, Ivy can: retrieve modules from Maven Central with no con guration, via its public default repository access any other Maven repo - especially Maven local - just via minimal con guration extract a default set of con gurations from a POM - by converting the POM into an Ivy descriptor convert an Ivy descriptor to a POM, mapping con gurations to Maven scopes publish to a Maven repo, with no published ivy.xml 113
  114. Module attributes equivalence Similarities in modules attributes can be summed

    up in the following table: Ivy concept Ivy attribute Maven POM attribute Organisation organisation groupId Module name module artifactId Revision revision version 114
  115. De ning a Maven resolver To access, for example, the

    local Maven repo, you should add the following resolver to ivysettings.xml <resolvers> <filesystem name="local-m2" m2compatible="true"> <!-- Important attribute --> <ivy pattern="ROOT/[module]-[revision].pom" /> <artifact pattern="ROOT/[artifact]-[revision].[ext]"/> </filesystem> </resolvers> where ROOT should actually be replaced with: ${user.home}/.m2/repository/[organisation]/[module] /[revision] 115
  116. The m2compatible attribute Resolvers such as lesystem and ibiblio support

    the m2compatible attribute; when it is set to true, the resolver behaves in a way similar to Maven: dots in [organisation] are converted into /, thus generating a longer path within the repository the resolver will look for POM descriptors transitive dependencies of POMs are enabled 116
  117. Generated conf from Maven POM When depending on a module

    having a Maven POM, Ivy creates an ivy.xml in its repo cache having these confs: default: master artifact + runtime dependencies master: just the master artifact, with no transitive dependencies Maven scopes: compile, provided, runtime, test sources, javadoc - especially for IDE support optional, to get all the optional dependencies 117
  118. Depending on Maven scopes For most Maven dependencies, you should

    depend on the default con guration, which provides: Maven's master artifact Its transitive runtime dependencies So, your conf mapping for a Maven dependency should be something like X->default, where X denotes one or more master con gurations; for simplicity, consider using also defaultconf and defaultconfmapping 118
  119. Creating a POM le 1. Use Ant's ivy:makepom task in

    build.xml: <ivy:makepom ivyfile="ivy.xml" pomfile="dist/${}.pom" /> 2. In ivy.xml, declare a dedicated artifact: <publications> ... <artifact type="pom" /> ... </publications> 119
  120. De ning Maven scopes To associate both dependencies and artifacts

    to Maven scopes, just create con gurations that are named like them: compile, provided, runtime and test. When creating the POM, Ivy will keep track of the mapping, assigning con guration dependencies to each scope. 120
  121. Further POM customization Via attributes and subtags of ivy:makepom you

    can: De ne a mapping between Ivy con gurations and Maven scopes; the default mapping is by name, but you can manually perform a custom mapping between con gurations and scopes. Unmapped con guration will create, in the POM, unscoped optional dependencies Add further dependencies to the POM only Use a custom POM template, receiving injected Ivy variables 121
  122. Locating the generated POM In build.xml, con gure ivy:publish by

    adding an artifacts subtag, using a pattern: <ivy:publish resolver="local-m2" overwrite="true" publishivy="false"> ... <artifacts pattern="dist/${}.[ext]" /> </ivy:publish> The resolver attribute should point to a Maven repository resolver (having m2compatible=true) If you want to publish for Maven only, you can set publishivy to false 122
  123. Section 5 Conclusion

  124. Example project on GitHub To start playing with Ivy, you

    can explore the related GitHub project: It consists of many subprojects featuring: a lot of explanatory comments what-if scenarios interesting cases studies, especially Maven compatibility 124
  125. Final considerations We have come to the end of this

    introduction to Ivy: I hope you have found it a useful and structured guide to Ivy's vast universe of exibility! The best way to learn Ivy is now to practice a lot, always experimenting new ideas and keeping an eye on the online documentation. Thanks for your attention! ^__^ 125