简体   繁体   中英

Excluding an Ivy dependency conditionally

I need to build a custom Ant script that builds a project based on CI output. We use Atlassian Bamboo as CI server.

Normally our projects have a dependency to our platform module, managed via Ivy/Artifactory.

Our typical dependencies.xml file contains a dependency to that module, transitively. And other potential dependencies. As an example, our core module depends on lots of Spring packages, but not on Spring Boot. If a project needs Spring Boot too, it will define its dependency in its dependencies.xml file along with <depencency org="com.acme" name="core-platform"...

My goal now is to exclude com.acme#core-platform from resolution, because I am making a different task that uses Bamboo output artifact to take the latest build of the core module and its dependencies without going through Artifactory.

This is very important because during a build I may like to change the version of a dependent package (eg upgrade Spring 4.3.1 to 4.3.3) and test with the proper Spring. If I simply resolve dependencies to com.acme#core-platform#latest.release , which is released on Artifactory, I won't take 4.3.3 of Spring which was committed to Git and available in core-platform 's currently-building dependencies.xml . I hope my explanation is easy to understand.

So let's say I have this dependency list as an example

    com.acme#core-platform#${version}
    org.hibernate#hibernate-java8#5.1.0.Final
    org.springframework.boot#spring-boot-starter-web#1.3.1.RELEASE
    commons-collections#commons-collections#3.2.2
    .... others

Full dependency is

<dependencies>  
    <dependency org="com.acme"              name="core-platform"          rev="${version}"         transitive="true"      conf="runtime->runtime" changing="true"/>
    <dependency org="com.acme"              name="core-platform"          rev="${version}"         transitive="true"      conf="compile->compile" changing="true"/>
    <dependency org="com.acme"              name="core-platform"          rev="${version}"         transitive="true"      conf="provided->provided" changing="true"/>
    <dependency org="com.acme"              name="core-platform"          rev="${version}"         transitive="true"      conf="junit->junit" changing="true"/>
    <dependency org="com.acme"              name="core-platform"          rev="${version}"         transitive="true"      conf="test->test" changing="true"/>



    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-java8 -->
    <dependency org="org.hibernate" name="hibernate-java8" rev="5.1.0.Final" transitive="false" />


    <dependency org="org.springframework.boot"  name="spring-boot-starter-web"          rev="1.3.1.RELEASE"                 transitive="false" />
    <dependency org="org.springframework.boot"  name="spring-boot-starter-tomcat"       rev="1.3.1.RELEASE"                 transitive="false" />
    <dependency org="org.springframework.boot"  name="spring-boot-starter-validation"   rev="1.3.1.RELEASE"                 transitive="false" />


    <dependency org="commons-collections"               name="commons-collections"              rev="3.2.2"             transitive="false" />


    <!-- jackson2 libs -->
    <dependency org="com.fasterxml.jackson.datatype"    name="jackson-datatype-jdk8"            rev="2.8.1"             transitive="false"          conf="runtime->*"/>
    <dependency org="com.fasterxml.jackson.datatype"    name="jackson-datatype-jsr310"          rev="2.8.1"             transitive="false"          conf="runtime->*"/>


    <exclude module="joda-time" />
    <exclude module="jackson-datatype-joda" />
</dependencies>

I simply want to take Hibernates' Java8, commons-collections, etc.

  1. Creating a duplicate dependencies.xml is not an option
  2. I was considering manipulating the dependencies.xml via Ant and have it exclude the acme modules by regex. Feasible but tricky
  3. Unfortunately I can't combine Ant task's ivy:retrieve with attributes file and element exclude , because that would have helped a looooooot

Any ideas?

It is hard to understand your requirement. I suspect that your problem could be solved by creating an additional configuration and use configuration mappings to control the downloads.

Example

This build creates two directories. The first contains the log4j dependency without transitive dependencies, the second includes the remote module's optional dependencies. If you look at the remote POM you'll see they have a different scope.

├── build.xml
├── ivy.xml
├── lib1
│   └── log4j-1.2.17.jar
└── lib2
    ├── activation-1.1.jar
    ├── geronimo-jms_1.1_spec-1.0.jar
    ├── log4j-1.2.17.jar
    └── mail-1.4.3.jar

build.xml

<project name="demo" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">

  <target name="resolve">
    <ivy:resolve/>

    <ivy:retrieve pattern="lib1/[artifact]-[revision](-[classifier]).[ext]" conf="noDependencies"/>
    <ivy:retrieve pattern="lib2/[artifact]-[revision](-[classifier]).[ext]" conf="withDependencies"/>
  </target>

</project>

Notes:

  • Each "retrieve" task creates a directory containing the files that make up the configuration.

ivy.xml

<ivy-module version="2.0">
  <info organisation="com.myspotontheweb" module="demo"/>

  <configurations>
    <conf name="noDependencies" description="File grouping that has no transitive dependencies"/>
    <conf name="withDependencies" description="File grouping that contains dependencies"/>
  </configurations>

  <dependencies>
    <dependency org="log4j" name="log4j" rev="1.2.17" conf="noDependencies->master; withDependencies->master,optional"/>
  </dependencies>

</ivy-module>

Notes:

  • Note how the configuration is declared at the top of the ivy file and the dependency contains two configuration mappings

Additional

The following answer explains how ivy interprets Maven modules. It creates configurations that can be used to decide which files should be downloaded:

Ok, looks like the replace trick is very easy too.

  1. Add the following markers <!-- DEPS START --> and <!-- DEPS END --> (or any of choice) between the parts of the dependencies.xml file to ignore
  2. Hack via Ant

     <copy file="dependencies.xml" tofile="ci/hacked-dependencies.xml" overwrite="true"> <filterchain> <replacestring from="&lt;!-- DEPS START --&gt;" to="&lt;!--" /> <replacestring from="&lt;!-- DEPS END --&gt;" to="--&gt;" /> </filterchain> </copy> 

Example

    <!-- DEPS START --> 
    <dependency org="com.acme" name="core-platfrom" rev="${version}" transitive="true" conf="runtime->runtime"/>
    <!-- DEPS END -->

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM