Is there a way to specify the location of a local jsch.jar from within build.xml?

13,198

Solution 1

Finally I found a working solution (for Ant 1.7.1 at least). First you have to remove ant-jsch.jar from ANT_HOME/lib as Ant complains about it and gets confused. Then load libraries from the project itself:

<available property="ant-jsch.present" file="${ant.home}/lib/ant-jsch.jar"/>
<fail if="ant-jsch.present" message="Please remove ant-jsch.jar from ANT_HOME/lib see [http://ant.apache.org/faq.html#delegating-classloader]"/>

<path id="jsch.path">
    <pathelement location="lib/ant-jsch.jar" />
    <pathelement location="lib/jsch-0.1.44.jar" />
</path>

<taskdef name="scp" classname="org.apache.tools.ant.taskdefs.optional.ssh.Scp" classpathref="jsch.path" />
<taskdef name="sshexec" classname="org.apache.tools.ant.taskdefs.optional.ssh.SSHExec" classpathref="jsch.path" />

Solution 2

So, this question is old, but I devised another approach which may help others. We can spawn Ant from a <java> task with the proper classpath to run <scp>. This avoid the classpath leaking problem, and doesn't requires changing Ant install in any way:

<target name="sendfile">
    <!-- file: local file to send -->
    <!-- todir: remote directory -->
    <java classname="org.apache.tools.ant.launch.Launcher"
        fork="true" dir="${basedir}" taskname="ant+scp">
        <classpath>
            <pathelement location="/where/is/jsch-0.1.49.jar"/>
            <pathelement location="${ant.home}/lib/ant-launcher.jar"/>
        </classpath>
        <arg value="-buildfile"/>
        <arg file="${ant.file}"/>
        <arg value="-Dfile=${file}"/>
        <arg value="-Dtodir=${todir}"/>
        <arg value="sendfile.scp"/>
    </java>
</target>

<target name="sendfile.scp">
    <echo message="Sending ${file} to ${todir}"/>
    <property file="/tmp/passwordfile"/>
    <scp file="${file}" todir="[email protected]:${todir}"
        trust="true" port="22" password="${PASSWORD}"/>
</target>

The port parameter isn't needed, but it's here as a reminder for custom SSH ports. The password is a property stored on /tmp/passwordfile, like PASSWORD=mysecretpassword. Change these to suit your needs. Here follows an usage example:

<ant target="sendfile">
    <!-- Example: send /etc/os-release file to remote dir /home/myself -->
    <property name="file" value="/etc/os-release"/>
    <property name="todir" value="/home/myself"/>
</ant>

Solution 3

For reference, an approach that I find useful is to repackage the jars, so they don't conflict - you can do this in Ant using JarJar like this:

<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpath="${basedir}/lib/build/jar/jarjar-1.4.jar"/>

<taskdef name="scp" classname="repackaged.scp.org.apache.tools.ant.taskdefs.optional.ssh.Scp" classpath="${basedir}/lib/build/jar/repackaged-scp.jar"/>

<target name="repackage.scp" description="Repackages Ant's optional SCP task and the JSch implementation to avoid conflicting with one on Ant's classpath">
    <delete file="${basedir}/lib/build/jar/repackaged-scp.jar" failonerror="false"/>
    <jarjar basedir="." jarfile="${basedir}/lib/build/jar/repackaged-scp.jar" includes="nothing">
        <zipfileset src="${basedir}/lib/build/jar/ant-jsch-1.9.1.jar"/>
        <zipfileset src="${basedir}/lib/build/jar/jsch-0.1.50.jar"/>
        <rule pattern="com.jcraft.jsch.**" result="repackaged.scp.com.jcraft.jsch.@1"/>
        <rule pattern="org.apache.tools.ant.taskdefs.optional.ssh.**" result="repackaged.scp.org.apache.tools.ant.taskdefs.optional.ssh.@1"/>
    </jarjar>
</target>

Solution 4

I was able to solve this issue following post from here https://stackoverflow.com/a/858744/3499805 and then

<taskdef resource="net/jtools/classloadertask/antlib.xml" classpath="${basedir}/ant-lib/ant-classloadertask.jar" />
<classloader loader="system" classpath="${basedir}/ant-lib/jsch-0.1.54.jar"/>
Share:
13,198
Pankaj Sharma
Author by

Pankaj Sharma

Updated on July 23, 2022

Comments

  • Pankaj Sharma
    Pankaj Sharma almost 2 years

    build.xml contains <scp> and <sshexec> tasks, so I provide jsch.jar and other libraries in the same directory together with build.xml.

    The following taskdef:

    <taskdef name="scp"
        classname="org.apache.tools.ant.taskdefs.optional.ssh.Scp"
        classpath="WebContent/WEB-INF/lib/jsch-0.1.43.jar" />
    

    throws an error

    A class needed by class org.apache.tools.ant.taskdefs.optional.ssh.Scp
    cannot be found: com/jcraft/jsch/UserInfo
    

    I cannot modify the standard Ant installation (e.g. put jsch.jar in ant lib directory, or remove ant-jsch.jar), or add command-line flags, or modify system environment variables, etc.: the script has to run with default Ant on different systems.

    I'm actually reposting the question originally asked here: http://ant.1045680.n5.nabble.com/specifying-location-of-an-external-library-within-build-xml-td1344969.html

    but could not get the answer about classloader to work.

  • gMale
    gMale over 12 years
    It seems this is a common problem and I think this is the best solution, except instead of failing, I'm going to just go ahead and delete the /lib/ant-jsch.jar. In case it helps others, Paulo gives an explanation of the core issue in his SO answer to a related SCP question and the same problem occurs with junit and is explained here
  • Ed Randall
    Ed Randall almost 8 years
    But this requires modification of the standard Ant installation.
  • Edward Kennedy
    Edward Kennedy over 6 years
    I've been grappling with this issue for days and this solution is the only one that I could get to work!