2010-09-16 20 views
8

build.xml contiennent les tâches <scp> et <sshexec>, donc je fournis jsch.jar et autres bibliothèques dans le même répertoire avec build.xml.Existe-t-il un moyen de spécifier l'emplacement d'un fichier jsch.jar local dans build.xml? Les tâches

Le taskdef suivant:

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

renvoie une erreur

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

Je ne peux pas modifier la norme d'installation Ant (par exemple, mettre jsch.jar dans ant lib , ou supprimer des fourmis jsch. jar), ou ajouter des drapeaux de ligne de commande, ou modifier variables d'environnement système, etc .: le script doit fonctionner avec Ant par défaut sur différents systèmes.

Je suis en fait reposter la question posée ici à l'origine: http://ant.1045680.n5.nabble.com/specifying-location-of-an-external-library-within-build-xml-td1344969.html

mais n'a pas pu obtenir la réponse au sujet classloader au travail.

Répondre

17

Enfin, je trouve une solution de travail (pour 1.7.1 Ant au moins). D'abord vous devez supprimer ant-jsch.jar de ANT_HOME/lib comme Ant se plaint à ce sujet et devient confus. Puis charger les bibliothèques du projet lui-même:

<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

Il semble que ce soit un problème commun et je pense que c'est la meilleure solution, sauf au lieu d'échouer, je vais juste aller de l'avant et de supprimer le/lib/ant -jsch.jar. Dans le cas où cela aide les autres, Paulo donne une explication du problème central dans son SO [réponse à une question SCP connexe] (http://stackoverflow.com/questions/5796587/problems-with-ant-optional-tasks-sshexec- et-scp-classpath-issue) et [le même problème se produit avec junit et est expliqué ici] (http://ant.apache.org/faq.html#delegating-classloader) – gMale

+1

Mais cela nécessite une modification de l'installation Ant standard . –

+0

J'ai été aux prises avec ce problème pendant des jours et cette solution est la seule que j'ai pu travailler! –

0

Créer une référence de chemin, puis l'utiliser dans votre définition de tâche:

<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

Donc, cette question est ancienne, mais j'ai conçu une autre approche qui peut aider les autres. Nous pouvons générer Ant à partir d'une tâche <java> avec le chemin de classe approprié pour exécuter <scp>. Cela permet d'éviter le problème des fuites classpath, et ne nécessite un changement Ant installer de quelque façon que:

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

Le paramètre port n'est pas nécessaire, mais il est ici comme un rappel pour les ports SSH personnalisés. Le mot de passe est une propriété stockée sur /tmp/passwordfile, comme PASSWORD=mysecretpassword. Changez-les pour répondre à vos besoins. suit Voici un exemple d'utilisation:

<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

Pour référence, une approche que je trouve utile est de reconditionner les pots, donc ils ne sont pas incompatibles - vous pouvez le faire dans Ant en utilisant JarJar comme ceci:

<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

Créez ~/.ant/lib et copiez-y jsch.jar dans le cadre de l'initialisation de la génération.

<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

j'ai pu résoudre ce problème d'ici après suivant https://stackoverflow.com/a/858744/3499805 puis

<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

Il y a un bien connu trick avec URLClassLoader. En l'utilisant, nous pouvons rendre jsch accessible à ant-jsch.

Je me demande comment fonctionne classloadertask depuis la réponse 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"; 
}