2010-09-16 24 views
8

build.xml contiene tareas <scp> y <sshexec>, así que proporciono jsch.jar y otras bibliotecas en el mismo directorio junto con build.xml.¿Hay alguna forma de especificar la ubicación de un jsch.jar local desde dentro de build.xml?

La siguiente taskdef:

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

lanza un error

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

No puedo modificar la instalación Ant estándar (por ejemplo, poner en jsch.jar hormiga lib o eliminar hormigas jsch. jar), o agregue indicadores de línea de comando, o modifique las variables de entorno del sistema , etc .: el script debe ejecutarse con Ant predeterminado en diferentes sistemas.

estoy realmente volver a colocar la pregunta originalmente pedido aquí: http://ant.1045680.n5.nabble.com/specifying-location-of-an-external-library-within-build-xml-td1344969.html

pero no pudieron obtener la respuesta sobre el cargador de clases para trabajar.

Respuesta

17

Finalmente encontré una solución de trabajo (por Ant 1.7.1 por lo menos). Primero tiene que eliminar ant-jsch.jar de ANT_HOME/lib ya que Ant se queja y se confunde. A continuación, las bibliotecas de carga desde el propio proyecto:

<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" /> 
+1

Parece que este es un problema común y creo que esta es la mejor solución, pero en lugar de en su defecto, voy a seguir adelante y eliminar el directorio/lib/ant -jsch.jar. En caso de que ayude a otros, Paulo da una explicación del problema central en su OE [respuesta a una pregunta relacionada con el CPS] (http://stackoverflow.com/questions/5796587/problems-with-ant-optional-tasks-sshexec- and-scp-classpath-issue) y [el mismo problema ocurre con junit y se explica aquí] (http://ant.apache.org/faq.html#delegating-classloader) – gMale

+1

Pero esto requiere la modificación de la instalación estándar de Ant. . –

+0

¡He estado lidiando con este problema por días y esta solución es la única que podría ponerme a trabajar! –

0

Crear una referencia de la trayectoria y luego utilizarlo en su definición de la tarea:

<path id="ssh.path"> 
    <pathelement location="${lib1.dir}/helloworld.jar"/> 
    <fileset dir="${lib2.dir}"> 
     <include name="*.jar"/> 
    </fileset> 
</path> 

<taskdef name="mytask" classname="org.mytask" classpathref="ssh.path" /> 
3

Por lo tanto, esta cuestión es viejo, pero yo inventamos otro enfoque que puede ayudar a los demás. Podemos generar Ant desde una tarea <java> con el classpath adecuado para ejecutar <scp>. Esto evita la fuga de ruta de clases de problemas y no requiere cambiar Ant instalar en cualquier forma:

<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> 

El parámetro port no es necesaria, pero es aquí como un recordatorio para los puertos SSH personalizado. La contraseña es una propiedad almacenada en /tmp/passwordfile, como PASSWORD=mysecretpassword. Cambie estos para adaptarse a sus necesidades. Aquí sigue un ejemplo de uso:

<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> 
2

Como referencia, un enfoque que me parece útil es para volver a empaquetar los frascos, de modo que no entren en conflicto - usted puede hacer esto en Ant usando JarJar así:

<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="[email protected]"/> 
     <rule pattern="org.apache.tools.ant.taskdefs.optional.ssh.**" result="[email protected]"/> 
    </jarjar> 
</target> 
0

Crea ~/.ant/lib y copia jsch.jar como parte de la inicialización de compilación.

<target name="init"> 
    <property name="user.ant.lib" location="${user.home}/.ant/lib"/> 
    <mkdir dir="${user.ant.lib}"/> 
    <copy todir="${user.ant.lib}"> 
    <fileset dir="${basedir}/build/tools" includes="jsch-*.jar"/> 
    </copy> 
</target> 
1

que era capaz de resolver este problema siguiente post de aquí https://stackoverflow.com/a/858744/3499805 y luego

<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"/> 
0

está ahí un conocido trick con URLClassLoader. Al usarlo podemos hacer que jsch sea accesible a ant-jsch.

Me pregunto cómo funciona classloadertask de la respuesta de @ user3499805.

<target name="injectJsch" description="inject jsch jar"> 
    <makeurl file="${acdc.java.tools}/lib/jsch-0.1.50.jar" property="jsch.jar.url"/> 
    <taskdef name="injectJsch" 
     classname="tools.deployments.ant.InjectJsch" 
     classpath="${basedir}/jars/ajwf_deploytools.jar" 
    /> 
    <injectJsch jarLocation="${jsch.jar.url}"/> 
</target> 

_

package tools.deployments.ant; 

import java.lang.reflect.Method; 
import java.net.URL; 
import java.net.URLClassLoader; 

import org.apache.tools.ant.BuildException; 
import org.apache.tools.ant.Task; 
import org.apache.tools.ant.taskdefs.optional.ssh.LogListener; 

public class InjectJsch extends Task { 

    public void setJarLocation(final String jarLocation) { 
     this.jarLocation = jarLocation; 
    } 

    @Override 
    public void execute() throws BuildException { 
     try { 
      injectJsch(new URL(jarLocation)); 
     } catch (final Exception e) { 
      throw new BuildException(e); 
     } 
    } 

    public static void injectJsch(final URL jarLocation) throws Exception { 
     ClassLoader parent = LogListener.class.getClassLoader(); 
     try { 
      parent.loadClass(TESTCLASS); 
     } catch (final ClassNotFoundException e) { 
      final Method addURLmethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); 
      addURLmethod.setAccessible(true); 
      ClassLoader cl; 
      do { 
       cl = parent; 
       if (cl instanceof URLClassLoader) { 
        addURLmethod.invoke(cl, jarLocation); 
        break; 
       } 
       parent = cl.getParent(); 
      } while (parent != cl && parent != null); 
      LogListener.class.getClassLoader().loadClass(TESTCLASS); 
     } 

    } 

    private String jarLocation; 

    private static final String TESTCLASS = "com.jcraft.jsch.UserInfo"; 
} 
Cuestiones relacionadas