java 有没有办法从 build.xml 中指定本地 jsch.jar 的位置?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3726608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 03:10:51  来源:igfitidea点击:

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

javaantscp

提问by Tomasz

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

build.xml 包含<scp><sshexec>tasks,所以我把jsch.jar 等库和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.

我无法修改标准的 Ant 安装(例如将 jsch.jar 放在 ant lib 目录中,或删除 ant-jsch.jar),或添加命令行标志,或修改系统环境变量等:脚本必须以默认方式运行不同系统上的蚂蚁。

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

我实际上是在重新发布最初在这里提出的问题: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.

但无法得到有关类加载器工作的答案。

回答by igor

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

最后我找到了一个可行的解决方案(至少对于 Ant 1.7.1)。首先,您必须ant-jsch.jarANT_HOME/libAnt 抱怨它并感到困惑时将其删除。然后从项目本身加载库:

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

回答by Marcond

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:

所以,这个问题很旧,但我设计了另一种可能对其他人有帮助的方法。我们可以从<java>具有正确类路径的任务中生成 Ant来运行<scp>。这避免了类路径泄漏问题,并且不需要以任何方式更改 Ant 安装:

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

port参数不是必需的,但它在这里是为了提醒自定义 SSH 端口。密码是存储在 上的属性/tmp/passwordfile,例如PASSWORD=mysecretpassword。更改这些以满足您的需求。下面是一个使用示例:

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

回答by Mark Slater

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:

作为参考,我发现一种有用的方法是重新打包 jar,这样它们就不会发生冲突 - 您可以在 Ant 中使用 JarJar 执行此操作,如下所示:

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

回答by user3499805

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

我能够在https://stackoverflow.com/a/858744/3499805 的帖子之后解决这个问题 ,然后

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

回答by basin

There's a well-known trickwith URLClassLoader. By using it we can make jschaccessible to ant-jsch.

有一个众所周知的伎俩URLClassLoader。通过使用它,我们可以jsch访问ant-jsch.

I wonder how classloadertaskfrom the answer by @user3499805 works.

我想知道classloadertask@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";
}

回答by Mark O'Connor

Create a path reference and then use it in your task definition:

创建一个路径引用,然后在您的任务定义中使用它:

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

回答by Ed Randall

Create ~/.ant/liband copy jsch.jarin there as part of the build initialisation.

作为构建初始化的一部分,在那里创建~/.ant/lib和复制jsch.jar

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