How can I specify the path of a JAR in an ant buildfile?
Asked Answered
C

3

8

I am executing lot of scp and sshexec and other remote commands from an ant build script. These commands don't work if jsch.jar isn't in the ant lib directory. To make it work, I copied the JAR into the ant lib directory, but this is not a good solution, as anyone else wanting to run the script would have to do the same thing. To run the ant target from Teamcity, we will have to explicitly set the path of the lib file.

Is there a way I can specify the path of the JAR in the ant build XML itself?

Charnel answered 24/2, 2011 at 12:15 Comment(3)
Have tested your ant code sample? I don't see a reason why it should not work. I use it the same way for other tasks.Novitiate
I am not saying it doesn't work, it works but I have to add the jsch.jar in the ant lib directory, which I want to avoid. Apologies, if my question does not state that properly. We have task like this { <scp todir="user1:pass1@server1:/tmp" trust="true" > <fileset dir="dir1"> <include name="file.txt" /> </fileset> </scp> } To make this work, I have to add jsch.jar in the ant lib manually. Can I avoid that by putting something in the build fileCharnel
The snippet that you have deleted also works if the jsch.jar is not in the lib directory. You then have to make sure you specify the correct relative or absolute path to it.Novitiate
C
5

Thanks all for your answers. I am managed to get it work with classloader task. This is what I did.

<project basedir="." >
  <property environment="env"/>

  <taskdef resource="net/jtools/classloadertask/antlib.xml">
    <classpath>
      <fileset dir="${basedir}/lib" includes="ant-classloader*.jar"/>
    </classpath>
  </taskdef>

  <!--Add JSCH jar to the classpath-->
  <classloader loader="system">
    <classpath>
      <fileset dir="${basedir}/lib" includes="jsch*.jar"/>
      </classpath>
  </classloader>

  <target name="Test">
      <scp todir="user1:pass1@server1:/tmp" trust="true" >
        <fileset dir="dir1">
          <include name="test.txt" />
        </fileset>
      </scp>
   </target>
</project>

As you can see here, I didn't have to give any dependant target for my "Test" target, it just works. It uses classloader, which appends jsch.jar to the system classloader.

Charnel answered 25/2, 2011 at 11:6 Comment(3)
I don't think the classloader is necessary. A path declaration at the top of your file would have worked fine, combined with a classpathref attribute on taskdef ant task.Fascinator
taskdef would have to be declared again, for which I would have to remove the ant-jsch.jar from lib directory and add nw taskdef for scp and sshexec.Charnel
This solution worked great. The classloader jar and information can be found at enitsys.sourceforge.net/ant-classloadertaskCrosier
M
2

One possible work around would be to use the -lib command line option to tell ant where to look for additional jars. Perhaps you could create a wrapper script that calls ant with this option set.

Another way would be to move the ant-jsch.jar file (this is the jar that comes with ant that defines the tasks, not the jsch.jar file you need to download separately) out of your ant lib directory, and create a taskdef for your ssh task separate to the built in one, then set the classpath for this task to the jsch.jar and the ant-jsch.jar:

<taskdef name="sshexec"
  classname="org.apache.tools.ant.taskdefs.optional.ssh.SSHExec">
  <classpath>
    <pathelement location="jsch-0.1.44.jar"/>
    <pathelement location="ant-jsch.jar" />
  </classpath>
</taskdef>

I'm not sure this will help you though, since it also involves making changes to the lib directory.

As far as I'm aware, it's not currently possible to specify the extra jars required for the built in tasks in the build file itself in general. There are some special cases, like junit for instance.

Muddy answered 24/2, 2011 at 16:35 Comment(2)
If there are troubles if the task requires more than one JAR why not simply mering all JARs into one JAR?Novitiate
I don't want to make changes to the ant lib directory as I don't have any control on it. This option wouldn't work in that scenarioCharnel
R
1

To ensure your build is more cross platform I'd suggest using dependency management. The ivy plug-in can automatically install the version of your build's plugin at build-time.

This approach means the last jar you'll ever need to install into your ANT lib is ivy-2.2.0.jar :-)

First declare your project's dependencies in the file ivy.xml

<ivy-module version="2.0">
    <info organisation="com.myspotontheweb" module="demo"/>
    <configurations>
        <conf name="anttask" description="Jars implementing ANT tasks"/>
    </configurations>
    <dependencies>
        <dependency org="com.jcraft" name="jsch" rev="0.1.42" conf="anttask->default"/>
    </dependencies>
</ivy-module>

Within your build.xml run ivy and use it to populate a custom classpath based on the ivy configuration:

<target name='init' description='Resolve project dependencies and set classpaths'>
    <ivy:resolve/>
    <ivy:cachepath pathid="anttask.path" conf="anttask"/>
</target>

Finally, elsewhere in your build declare your ANT tasks using the class path now automatically populated by ivy.

<target name='dosomething' depends="init">
    <taskdef name="sshexec" 
             classname="org.apache.tools.ant.taskdefs.optional.ssh.SSHExec"
             classpathref="anttask.path"/>
    ..
    ..
</target>

This approach works for all ANT plug-ins, most of which are available in the central Maven repository. The second benefit is that it's easy to upgrade the plug-in versions across all builds.

Railing answered 24/2, 2011 at 18:16 Comment(4)
This doesn't fix the problem of some jars needing to be in ants lib dir to satisfy the classloading requirements though. The actual ant task is defined in ant-jsch.jar which comes with ant, not in the jsch.jar downloaded separately. The problem is making jsch.jar visible to the classes in ant-jsch.jar. Or am I missing something?Muddy
Checkout the "classpathref" attribute on the taskdef task. It allows you to specify the class path to be used when declaring your task. The assistance ivy offers is the ability to download and populate that class path at build time. This is what the Maven build tool does, all it's plugins are downloaded.Fascinator
I quite like your approach, but again here each task will have to have call the init task first depends="init". I am looking for the option which is more like "change once and work for all" approach.Charnel
The init task would download all jars you specify in the ivy file. You then declare the tasks immediately or wait until you need them as in my example above. My example contains a single dependency. A typical build project would require 10-30 jars, not just for tasks, but for other frameworks like Spring and Hibernate. Please look at the Maven build tool some day. It will introduce you to new ideas on build management. The ivy plug-in enables to you support these yet keep using ANT as your primary build tool.Fascinator

© 2022 - 2024 — McMap. All rights reserved.