Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ivy to build a war with out copying jars to a lib directory

Tags:

ant

ivy

My goal is have my ant build script build a war file and include the jars that ivy knows this project depends on. The best code I could come up with at the moment is the following

<mkdir dir="dist/lib"/>
<ivy:retrieve pattern="dist/lib/[artifact].[ext]" sync="true"/>
<war destfile="dist/${ivy.module}.war" basedir="build" includes="**/*.class"
    webxml="${war.webxml}">
    <fileset dir="${war.web}"/>
    <lib dir="dist/lib"/>
</war>

The problem with this code is it copies the jars twice. Once in to my dist/lib directory and again in to the war when it's created. It works but I can't shake the feeling there is a better way.

What I would like to do is something more like the following

<ivy:cachepath pathid="locpathref.classpath"/>
<war destfile="dist/${ivy.module}.war" basedir="build" includes="**/*.class"
    webxml="${war.webxml}">
    <fileset dir="${war.web}"/>
    <lib refid="locpathref.classpath"/>
</war>

The problem is that the lib tag does not take in a refid of any kind. Any ideas or am I stuck with an extra set of file copies?

like image 940
AmaDaden Avatar asked Jan 16 '10 16:01

AmaDaden


2 Answers

The problem here is that the lib tag is a custom fileset that targets it's files into the war archive's lib sub directory. It might be possible to write a custom war task but I don't think it's worth the effort.

If want to improve the manner in which ivy manages your war's dependencies might I suggest using configurations?

Create a configuration describing the run-time dependencies:

    <ivy-module version="2.0">
    <info organisation="apache" module="hello-ivy"/>
    <configurations>
        <conf name="build" description="Libraries needed to for compilation"/>
        <conf name="war" extends="build" description="Libraries that should be included in the war file" />
    </configurations>
    <dependencies>
        <dependency org="commons-lang" name="commons-lang" rev="2.0" conf="build->*,!sources,!javadoc"/>
        <dependency org="commons-cli" name="commons-cli" rev="1.0" conf="build->*,!sources,!javadoc"/>
    </dependencies>
</ivy-module>

Afterwards you retrieve them into a dedicated directory (using a pattern) which can be simply included using the war task's lib tag:

    <ivy:retrieve pattern="${lib.dir}/[conf]/[artifact].[ext]"/>

    <war destfile="${war.file}" webxml="${resources.dir}/web.xml">
        <fileset dir="${resources.dir}" excludes="web.xml"/>
        <lib dir="${lib.dir}/war"/>
    </war>

The advantage of this approach is that you use the ivy conf attribute of each project dependency to ultimately decide if the jar gets included within the war file or not. The build file no longer cares.

In conclusion I understand that the point of your post was concern for multiple copies of your jar files... Using my suggested approach will further multiple your copies, but I would submit that this is not an issue provided you have a clean target to remove them afterwards.

like image 182
Mark O'Connor Avatar answered Nov 15 '22 09:11

Mark O'Connor


If you're using Ant 1.8, you can use the technique described here: http://www.beilers.com/2010/06/ivy-dependency-management-lessons-learned-and-ant-1-8-mapped-resources/

EXAMPLE:

<war destfile="${war.full.path}" webxml="WebContent/WEB-INF/web.xml" manifest="${manifest.path}">
    <fileset dir="WebContent">
     </fileset>
    <classes dir="${build.dir}"/>

    <mappedresources>
      <restrict>
        <path refid="classpath.CORE"/>
        <type type="file"/>
      </restrict>
      <chainedmapper>
        <flattenmapper/>
        <globmapper from="*" to="WEB-INF/lib/*"/>
      </chainedmapper>
    </mappedresources>

    <zipfileset dir="src" prefix="WEB-INF/classes">
         <include name="**/resources/**/*.properties" />
         <include name="**/resources/**/*.xml" />
    </zipfileset>
</war>
like image 27
Snekse Avatar answered Nov 15 '22 08:11

Snekse