How to avoid copying dependencies with Ivy
Asked Answered
B

3

9

I'm looking into using Ivy to manage dependencies but wow - that thing really likes to make multiple copies of jars! It spreads like the ivy in my back yard and is just as undesirable!

Is it possible to have Ivy simply define a classpath (for a specified profile) that references the resolved dependencies so my javac can reference them directly in the ivy repository (or cache?).

I've read the reference docs buy only see the option to set up symbolic links to the repository cache. I guess this will suffice, but it seems like a waste. Also, I'm not sure that a "war" task can build the war from symbolic links... but I guess I'll find out when I give it a try.

Any better suggestions?

Brython answered 9/4, 2010 at 17:16 Comment(0)
D
16

Here's my standard Java build file that creates an executable jar.

The objective is to manage project specific stuff via a combination of ANT properties and an ivy.xml file for the 3rd-party dependencies.

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

  <property name="src.dir" location="src"/>
  <property name="build.dir" location="build"/>
  <property name="dist.dir" location="dist"/>
  <property name="dist.jar" location="${dist.dir}/${ant.project.name}.jar"/>
  <property name="dist.main.class" value="HelloWorld"/>

  <target name="retrieve">
    <ivy:resolve/>
    <ivy:cachepath pathid="build.path" conf="build"/>
    <ivy:cachepath pathid="runtime.path" conf="runtime"/>
  </target>

  <target name="compile" depends="retrieve">
    <mkdir dir="${build.dir}/classes"/>
    <javac srcdir="${src.dir}" destdir="${build.dir}/classes" classpathref="build.path"/>
  </target>

  <target name="build" depends="compile">
    <ivy:retrieve pattern="${dist.dir}/lib/[artifact].[ext]"/>

    <manifestclasspath property="jar.classpath" jarfile="${dist.jar}">
      <classpath>
        <fileset dir="${dist.dir}/lib" includes="*.jar"/>
      </classpath>
    </manifestclasspath>

    <jar destfile="${dist.jar}" basedir="${build.dir}/classes">
      <manifest>
        <attribute name="Main-Class" value="${dist.main.class}"/>
        <attribute name="Class-Path" value="${jar.classpath}"/>
      </manifest>
    </jar>
  </target>

  <target name="clean">
    <delete dir="${build.dir}"/>
    <delete dir="${dist.dir}"/>
  </target>

</project>

As you've discovered in the Ivy docu, the cachepath Ivy task is used to manage two ANT paths. One for the build dependencies the other for the run-time dependencies of the executable jar.

The real power of Ivy is in something called configurations. I found it difficult to grasp initially until I realised it was simple a logical grouping of jars that I can define for my project. This example has two configurations:

  • build
  • runtime

Here's the ivy file demonstrating how dependencies can be associated with configurations:

<ivy-module version="2.0">
    <info organisation="com.myspotontheweb" module="demo"/>
    <configurations>
        <conf name="build" description="Libraries needed to for compilation"/>
        <conf name="runtime" extends="build" description="Libraries that need to be included with project jar" />
    </configurations>
    <dependencies>
        <dependency org="commons-lang" name="commons-lang" rev="2.0" conf="build->default"/>
        <dependency org="commons-cli" name="commons-cli" rev="1.0" conf="runtime->default"/>
    </dependencies>
</ivy-module>

In conclusion I hope this example helps in understanding Ivy. I like the way it concentrates on only one thing, the management of 3rd-party dependencies.

Downs answered 9/4, 2010 at 22:25 Comment(3)
Detailed and well written. Thanks, this is helpful.Goodnight
Note that it could be needed to restrict cachepath with type="jar" and that cached path can also be used directly for packaging: https://mcmap.net/q/1134014/-how-to-avoid-copying-dependencies-with-ivyNancynandor
@Nancynandor I have never seen the need to restrict the configurations. Normally the configuration mapping (to the remote "default" configuration) does a good job of making sure only jar artifacts are included.Conlon
B
3

After battling through the badly written Ivy documentation (sigh - what is wrong with these people? - did they not attend high-school literacy classes in any language?), I see there is a post-resolve task called cachepath that will construct an ant path to the resolved dependency artifacts instead of copying files to a lib directory. This might be just what I'm looking for!

Brython answered 9/4, 2010 at 19:6 Comment(2)
I give up! The Ivy documentation is SO BAD it makes the entire framework utterly useless. I'm going to have to write my own dependency management build configuration.Brython
Wouldn't it be better to be the solution and create better doc for ivy? That seems like less to maintain than an entire dep management systemKruter
N
3

Just to augment @Mark's answer.

Note that cachepath result can also be directly used in build without the need to copy jars with retrieve:

<target name="build" depends="compile">
    <jar destfile="${dist.ear}">
        <mappedresources>
            <resources refid="runtime.path"/>
            <chainedmapper>
                <flattenmapper/>
                <globmapper from="*" to="lib/*"/>
            </chainedmapper>
        </mappedresources>
    </jar>
</target>
Nancynandor answered 7/10, 2013 at 9:9 Comment(3)
+1 Clever idea. I've done this in the past by first using an ivy retrieve task to create a temp staging directory in order to build the WAR or EAR file.Conlon
@Mark, would you be so kind to share any thoughts on #19227504, please?Nancynandor
I saw it, but don't know any way to easily subtract dependencies from an ivy configuration.Conlon

© 2022 - 2024 — McMap. All rights reserved.