2010-09-16 8 views
8

build.xml zawiera zadania <scp> i <sshexec>, więc udostępniam jsch.jar i inne biblioteki w tym samym katalogu razem z plikiem build.xml.Czy istnieje sposób określenia położenia lokalnego pliku jsch.jar z poziomu pliku build.xml?

Poniższy taskdef:

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

zgłasza błąd

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

nie mogę modyfikować standardowej instalacji Ant (np umieścić jsch.jar w ant lib katalogu lub usunąć ant-jsch. jar) lub dodaj flagi linii poleceń lub zmodyfikuj zmienne systemowe systemu itp .: skrypt musi działać z domyślnym Ant w różnych systemach.

ja faktycznie przeksięgowanie pytanie pierwotnie zapytał tutaj: http://ant.1045680.n5.nabble.com/specifying-location-of-an-external-library-within-build-xml-td1344969.html

ale nie mógł uzyskać odpowiedź na temat classloader do pracy.

Odpowiedz

17

Wreszcie znalazłem roztwór roboczy (dla Ant 1.7.1 przynajmniej). Najpierw musisz usunąć ant-jsch.jar z ANT_HOME/lib, gdy Ant narzeka na to i myli się. Następnie załaduj biblioteki z samego projektu:

<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

Wydaje się że jest to powszechny problem i myślę, że jest to najlepsze rozwiązanie, z wyjątkiem zamiast braku, idę po prostu iść dalej i usunąć/lib/ant -jsch.jar. W przypadku, gdy pomaga innym, Paulo podaje wyjaśnienie podstawowego problemu w swojej SO [odpowiedź na powiązane pytanie SCP] (http://stackoverflow.com/questions/5796587/problems-with-ant-optional-tasks-sshexec- i-scp-classpath-issue) i [ten sam problem występuje z junitem i jest wyjaśniony tutaj] (http://ant.apache.org/faq.html#delegating-classloader) – gMale

+1

To jednak wymaga modyfikacji standardowej instalacji Ant . –

+0

Przez kilka dni zmagałem się z tym problemem, a to jedyne rozwiązanie, które mogłem dostać do pracy! –

0

Utwórz odniesienie do toru, a następnie używać go w swojej definicji zadanie:

<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

To pytanie jest stare, ale opracowałem inne podejście, które może pomóc innym. Możemy odrodzić Ant z zadania <java> z odpowiednią ścieżką klas, aby uruchomić <scp>. Tego uniknąć ścieżki klasy przecieka problemu i nie wymaga zmiany Ant zainstalować w dowolny sposób:

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

Parametr port nie jest potrzebne, ale to tutaj jako przypomnienie dla portów zwyczaj SSH. Hasło to właściwość przechowywana pod numerem /tmp/passwordfile, na przykład PASSWORD=mysecretpassword. Zmień je zgodnie z własnymi potrzebami. Tu następuje przykład wykorzystania:

<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

odsyłającym podejście, które uważam przydatna jest zapakowanie słoiki, więc nie są one sprzeczne - można to zrobić w Ant użyciu JarJar tak:

<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

Utwórz ~/.ant/lib i skopiuj jsch.jar tam jako część inicjalizacji kompilacji.

<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

udało mi się rozwiązać ten problem następujący wpis stąd https://stackoverflow.com/a/858744/3499805 a następnie

<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

Jest znanym trick z URLClassLoader. Za jego pomocą możemy udostępnić jsch dla ant-jsch.

Zastanawiam się, jak działa classloadertask z odpowiedzi użytkownika @3499805.

<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"; 
}