bodewig 2003/03/06 04:42:44
Modified: . WHATSNEW build.xml docs/manual install.html optionaltasklist.html src/main/org/apache/tools/ant/taskdefs defaults.properties Added: docs/manual/OptionalTasks scp.html src/main/org/apache/tools/ant/taskdefs/optional/ssh AbstractSshMessage.java Directory.java LogListener.java Scp.java ScpFromMessage.java ScpToMessage.java src/testcases/org/apache/tools/ant/taskdefs/optional/ssh ScpTest.java Log: <scp> Submitted by: charliehubbard76 at yahoo dot com Revision Changes Path 1.361 +3 -0 ant/WHATSNEW Index: WHATSNEW =================================================================== RCS file: /home/cvs/ant/WHATSNEW,v retrieving revision 1.360 retrieving revision 1.361 diff -u -r1.360 -r1.361 --- WHATSNEW 6 Mar 2003 12:04:59 -0000 1.360 +++ WHATSNEW 6 Mar 2003 12:42:43 -0000 1.361 @@ -157,6 +157,9 @@ * The <javadoc> task <tag> subelement has been enhanced to allow files with tag mappings to be used. +* New task <scp> that supports file transfers over SSH. Requires + jsch, a BSD licensed SSH library that can be found at + http://www.jcraft.com/jsch/index.html Changes from Ant 1.5.1 to Ant 1.5.2 ============================================= 1.354 +22 -1 ant/build.xml Index: build.xml =================================================================== RCS file: /home/cvs/ant/build.xml,v retrieving revision 1.353 retrieving revision 1.354 diff -u -r1.353 -r1.354 --- build.xml 26 Feb 2003 13:06:06 -0000 1.353 +++ build.xml 6 Mar 2003 12:42:43 -0000 1.354 @@ -155,7 +155,10 @@ </or> </selector> <selector id="needs.jdk1.4+"> - <filename name="${regexp.package}/Jdk14Regexp*"/> + <or> + <filename name="${regexp.package}/Jdk14Regexp*"/> + <filename name="${optional.package}/ssh/*"/> + </or> </selector> <!-- classes that should be present in Sun based JVMs, but not in @@ -289,6 +292,9 @@ <selector id="needs.swing"> <filename name="${optional.package}/splash/*"/> </selector> + <selector id="needs.jsch"> + <filename name="${optional.package}/ssh/*"/> + </selector> <patternset id="onlinetests"> <exclude name="**/GetTest.java" if="offline"/> <exclude name="**/SignJarTest.java" if="offline"/> @@ -543,6 +549,9 @@ <available property="beanshell.present" classname="bsh.StringUtil" classpathref="classpath"/> + <available property="jsch.present" + classname="com.jcraft.jsch.Session" + classpathref="classpath"/> </target> @@ -625,6 +634,7 @@ <selector refid="needs.jai" unless="jai.present"/> <selector refid="needs.jdepend" unless="jdepend.present"/> <selector refid="needs.swing" unless="swing.present"/> + <selector refid="needs.jsch" unless="jsch.present"/> </or> </not> </selector> @@ -792,6 +802,7 @@ <selector refid="needs.jai"/> <selector refid="needs.jdepend"/> <selector refid="needs.swing"/> + <selector refid="needs.jsch"/> </or> </not> </and> @@ -949,6 +960,13 @@ <selector refid="needs.weblogic.server"/> </or> </jar> + + <jar destfile="${build.lib}/${optional.jars.prefix}-jsch.jar" + basedir="${build.classes}" + manifest="${manifest.tmp}"> + <selector refid="needs.jsch"/> + </jar> + </target> <!-- Creates jar of test utility classes --> @@ -1616,6 +1634,9 @@ --> <exclude name="${ant.package}/taskdefs/AbstractCvsTaskTest.java" unless="have.cvs"/> + + <!-- test needs special setup --> + <exclude name="${optional.package}/ssh/ScpTest.java"/> </fileset> </batchtest> </junit> 1.47 +6 -0 ant/docs/manual/install.html Index: install.html =================================================================== RCS file: /home/cvs/ant/docs/manual/install.html,v retrieving revision 1.46 retrieving revision 1.47 diff -u -r1.46 -r1.47 --- install.html 24 Feb 2003 08:25:19 -0000 1.46 +++ install.html 6 Mar 2003 12:42:43 -0000 1.47 @@ -418,6 +418,12 @@ target="_top">http://gump.covalent.net/jars/latest/xml-commons/</a> for a nightly snapshot.</td> </tr> + <tr> + <td>jsch.jar</td> + <td>scp task</td> + <td><a href="http://www.jcraft.com/jsch/index.html" + target="_top">http://www.jcraft.com/jsch/index.html</a></td> + </tr> </table> <br> <hr> 1.35 +1 -0 ant/docs/manual/optionaltasklist.html Index: optionaltasklist.html =================================================================== RCS file: /home/cvs/ant/docs/manual/optionaltasklist.html,v retrieving revision 1.34 retrieving revision 1.35 diff -u -r1.34 -r1.35 --- optionaltasklist.html 7 Nov 2002 16:26:18 -0000 1.34 +++ optionaltasklist.html 6 Mar 2003 12:42:43 -0000 1.35 @@ -55,6 +55,7 @@ <a href="OptionalTasks/rpm.html">Rpm</a><br> <a href="OptionalTasks/serverdeploy.html">ServerDeploy</a><br> <a href="OptionalTasks/setproxy.html">Setproxy</a><br> +<a href="OptionalTasks/scp.html">Scp</a><br> <a href="OptionalTasks/script.html">Script</a><br> <a href="OptionalTasks/sound.html">Sound</a><br> <a href="OptionalTasks/sos.html">SourceOffSite</a><br> 1.1 ant/docs/manual/OptionalTasks/scp.html Index: scp.html =================================================================== <html> <head> <meta http-equiv="Content-Language" content="en-us"> <title>SCP Task</title> </head> <body> <h2><a name="scp">SCP</a></h2> <h3>Description</h3> <p>Copies a file or FileSet to or from a remote machine running SSH daemon. FileSet <i>only</i> works for copying files from the local machine to a remote machine.</p> <p><b>Note:</b> This task depends on external libraries not included in the Ant distribution. See <a href="../install.html#librarydependencies">Library Dependencies</a> for more information.</p> <h3>Parameters</h3> <table border="1" cellpadding="2" cellspacing="0"> <tr> <td valign="top"><b>Attribute</b></td> <td valign="top"><b>Description</b></td> <td align="center" valign="top"><b>Required</b></td> </tr> <tr> <td valign="top">file</td> <td valign="top">The file to copy. This can be a local path or a remote path of the form <i>user:[EMAIL PROTECTED]:/directory/path.</i></td> <td valign="top" align="center">Yes, unless a nested <code><fileset></code> element is used.</td> </tr> <tr> <td valign="top">todir</td> <td valign="top">The directory to copy to. This can be a local path or a remote path of the form <i>user:[EMAIL PROTECTED]:/directory/path</i></td> <td valian="top" align="center">Yes</td> </tr> <tr> <td valign="top">port</td> <td valign="top">The port to connect to on the remote host.</td> <td valian="top" align="center">No, defaults to 22.</td> </tr> <tr> <td valign="top">trust</td> <td valign="top">This trusts all unknown hosts if set to yes/true.</td> <td valian="top" align="center">No, defaults to No.</td> </tr> <tr> <td valign="top">knownhosts</td> <td valign="top">This sets the known hosts file to use to validate the identity of the remote host. This must be a SSH2 format file. SSH1 format is not supported.</td> <td valian="top" align="center">No, defaults to ${user.dir}/.ssh/known_hosts.</td> </tr> <tr> <td valign="top">failonerror</td> <td valign="top">Log a warning message, but do not stop the build, when the transfer does not work. </td> <td valign="top" align="center">No; defaults to true.</td> </tr> </table> <h3>Parameters specified as nested elements</h3> <h4>fileset</h4> <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select sets of files to copy. To use a fileset, the <code>todir</code> attribute must be set.</p> <h3>Examples</h3> <p><b>Copy a single local file to a remote machine</b></p> <pre> <scp file="myfile.txt" todir="user:[EMAIL PROTECTED]:/home/chuck"/> </pre> <p><b>Copy a single remote file to a local directory</b></p> <pre> <scp file="user:[EMAIL PROTECTED]:/home/chuck/myfile.txt" todir="../some/other/dir"/> </pre> <p><b>Copy a remote directory to a local directory</b></p> <pre> <scp file="user:[EMAIL PROTECTED]:/home/chuck/*" todir="/home/sara" /> </pre> <p><b>Copy a local directory to a remote directory</b></p> <pre> <scp todir="user:[EMAIL PROTECTED]:/home/chuck/"> <fileset dir="src_dir"/> </scp> </pre> <p><b>Copy a set of files to a directory</b></p> <pre> <scp todir="user:[EMAIL PROTECTED]:/home/chuck"> <fileset dir="src_dir"> <include name="**/*.java"/> </fileset> </scp> <scp todir="user:[EMAIL PROTECTED]:/home/chuck"> <fileset dir="src_dir" excludes="**/*.java"/> </scp> </pre> <p><strong>Security Note:</strong> Hard coding passwords and/or usernames in scp task can be a serious security hole. Consider using variable substituion and include the password on the command line. For example:<br> <pre> <scp todir="${username}:[EMAIL PROTECTED]:/dir" ...> </pre> Invoke ant with the following command line: <pre> ant -Dusername=me -Dpassword=mypassword target1 target2 </pre> </p> <p><strong>Unix Note:</strong> File permissions are not retained when files are copied; they end up with the default <code>UMASK</code> permissions instead. This is caused by the lack of any means to query or set file permissions in the current Java runtimes. If you need a permission- preserving copy function, use <code><exec executable="scp" ... ></code> instead. </p> <hr><p align="center">Copyright © 2003 Apache Software Foundation. All rights Reserved.</p> </body> </html> 1.140 +1 -0 ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties Index: defaults.properties =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties,v retrieving revision 1.139 retrieving revision 1.140 diff -u -r1.139 -r1.140 --- defaults.properties 4 Feb 2003 12:23:50 -0000 1.139 +++ defaults.properties 6 Mar 2003 12:42:44 -0000 1.140 @@ -181,6 +181,7 @@ chgrp=org.apache.tools.ant.taskdefs.optional.unix.Chgrp chown=org.apache.tools.ant.taskdefs.optional.unix.Chown attrib=org.apache.tools.ant.taskdefs.optional.windows.Attrib +scp=org.apache.tools.ant.taskdefs.optional.ssh.Scp # deprecated ant tasks (kept for back compatibility) starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java Index: AbstractSshMessage.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.taskdefs.optional.ssh; import com.jcraft.jsch.Session; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelExec; import java.io.IOException; import java.io.OutputStream; import java.io.InputStream; import java.text.NumberFormat; public abstract class AbstractSshMessage { protected Session session; protected LogListener listener = new LogListener() {; public void log(String message) { // do nothing; } }; public AbstractSshMessage(Session session) { this.session = session; } protected Channel openExecChannel( String command ) { ChannelExec channel = (ChannelExec) session.openChannel( "exec" ); channel.setCommand( command ); return channel; } protected void sendAck(OutputStream out) throws IOException { byte[] buf = new byte[1]; buf[0] = 0; out.write( buf ); out.flush(); } protected void waitForAck(InputStream in) throws IOException { int b = 0; do { b = in.read(); } while (b > 0); } public abstract void execute() throws IOException; public void setLogListener( LogListener aListener ) { listener = aListener; } protected void log( String message ) { listener.log( message ); } protected void logStats( long timeStarted, long timeEnded, int totalLength) { double duration = (timeEnded - timeStarted) / 1000.0; NumberFormat format = NumberFormat.getNumberInstance(); format.setMaximumFractionDigits( 2 ); format.setMinimumFractionDigits( 1 ); listener.log( "File transfer time: " + format.format( duration ) + " Average Rate: " + format.format( totalLength / duration ) + " B/s" ); } } 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java Index: Directory.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.taskdefs.optional.ssh; import java.util.ArrayList; import java.util.Iterator; import java.util.StringTokenizer; import java.io.File; public class Directory { private File directory; private ArrayList childDirectories; private ArrayList files; private Directory parent; public Directory( File directory ) { this( directory, null ); } public Directory( File directory , Directory parent ) { this.parent = parent; this.childDirectories = new ArrayList(); this.files = new ArrayList(); this.directory = directory; } public void addDirectory( Directory directory ) { if( !childDirectories.contains( directory ) ) childDirectories.add( directory ); } public void addFile( File file ) { files.add( file ); } public Iterator directoryIterator() { return childDirectories.iterator(); } public Iterator filesIterator() { return files.iterator(); } public Directory getParent() { return parent; } public boolean isRoot() { return parent == null; } public File getDirectory() { return directory; } public Directory getChild( File dir ) { for( int i = 0; i < childDirectories.size(); i++ ) { Directory current = (Directory) childDirectories.get(i); if( current.getDirectory().equals( dir ) ) { return current; } } return null; } public boolean equals(Object obj) { if( obj == this ) return true; if( !(obj instanceof Directory) ) return false; Directory d = (Directory)obj; return this.directory.equals( d.directory ); } public int hashCode() { return directory.hashCode(); } public String[] getPath() { return getPath( directory.getAbsolutePath() ); } public static String[] getPath( String thePath ) { StringTokenizer tokenizer = new StringTokenizer( thePath, File.separator ); String[] path = new String[ tokenizer.countTokens() ]; int i = 0; while( tokenizer.hasMoreTokens() ) { path[i] = tokenizer.nextToken(); i++; } return path; } public int fileSize() { return files.size(); } } 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java Index: LogListener.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.taskdefs.optional.ssh; public interface LogListener { void log( String message ); } 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java Index: Scp.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.taskdefs.optional.ssh; import com.jcraft.jsch.*; import java.io.*; import java.util.List; import java.util.LinkedList; import java.util.Iterator; import java.util.ArrayList; import org.apache.tools.ant.Task; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.FileSet; /** * Ant task for sending files to remote machine over ssh/scp. * * @author [EMAIL PROTECTED] * @since Ant 1.6 */ public class Scp extends Task implements LogListener { private String fromUri; private String toUri; private String knownHosts; private boolean trust = false; private int port = 22; private List fileSets = null; private boolean failOnError = true; public void setFailonerror( boolean failure ) { failOnError = failure; } /** * Sets the file to be transferred. This can either be a remote * file or a local file. Remote files take the form:<br> * <i>user:[EMAIL PROTECTED]:/directory/path/file.example</i><br> * Files to transfer can also include a wildcard to include all * files in a remote directory. For example:<br> * <i>user:[EMAIL PROTECTED]:/directory/path/*</i><br> * @param aFromUri a string representing the file to transfer. */ public void setFile(String aFromUri) { this.fromUri = aFromUri; } /** * Sets the location where files will be transferred to. * This can either be a remote directory or a local directory. * Remote directories take the form of:<br> * <i>user:[EMAIL PROTECTED]:/directory/path/</i><br> * This parameter is required. * @param aToUri a string representing the target of the copy. */ public void setTodir(String aToUri) { this.toUri = aToUri; } /** * Sets the path to the file that has the identities of * all known hosts. This is used by SSH protocol to validate * the identity of the host. The default is * <i>{$user.dir}/.ssh/known_hosts</i>. * @param knownHosts a path to the known hosts file. */ public void setKnownhosts( String knownHosts ) { this.knownHosts = knownHosts; } /** * Setting this to true trusts hosts whose identity is unknown. * * @param yesOrNo if true trust the identity of unknown hosts. */ public void setTrust( boolean yesOrNo ) { this.trust = yesOrNo; } /** * Changes the port used to connect to the remote host. * * @param port port number of remote host. */ public void setPort( int port ) { this.port = port; } /** * Adds a FileSet tranfer to remote host. NOTE: Either * addFileSet() or setFile() are required. But, not both. * * @param set FileSet to send to remote host. */ public void addFileset( FileSet set ) { if( fileSets == null ) { fileSets = new LinkedList(); } fileSets.add( set ); } public void init() throws BuildException { super.init(); this.toUri = null; this.fromUri = null; this.knownHosts = System.getProperty("user.dir") + "/.ssh/known_hosts"; this.trust = false; this.port = 22; this.fileSets = null; } public void execute() throws BuildException { if (toUri == null) { throw new BuildException("The 'todir' attribute is required."); } if ( fromUri == null && fileSets == null ) { throw new BuildException("Either the 'file' attribute or one " + "FileSet is required."); } boolean isFromRemote = false; if( fromUri != null ) isFromRemote = isRemoteUri(fromUri); boolean isToRemote = isRemoteUri(toUri); try { if (isFromRemote && !isToRemote) { download( fromUri, toUri ); } else if (!isFromRemote && isToRemote) { if( fileSets != null ) { upload( fileSets, toUri ); } else { upload( fromUri, toUri ); } } else if (isFromRemote && isToRemote) { // not implemented yet. } else { throw new BuildException("'todir' and 'file' attributes " + "must have syntax like the following: " + "user:[EMAIL PROTECTED]:/path"); } } catch (Exception e) { if( failOnError ) { throw new BuildException(e); } else { e.printStackTrace(); } } } private void download( String fromSshUri, String toPath ) throws JSchException, IOException { String[] fromValues = parseUri(fromSshUri); Session session = null; try { session = openSession(fromValues[0], fromValues[1], fromValues[2], port ); ScpFromMessage message = new ScpFromMessage( session, fromValues[3], new File( toPath ), fromSshUri.endsWith("*") ); log("Receiving file: " + fromValues[3] ); message.setLogListener( this ); message.execute(); } finally { if( session != null ) session.disconnect(); } } private void upload( List fileSet, String toSshUri ) throws IOException, JSchException { String[] toValues = parseUri(toSshUri); Session session = null; try { session = openSession( toValues[0], toValues[1], toValues[2], port ); List list = new ArrayList( fileSet.size() ); for( Iterator i = fileSet.iterator(); i.hasNext(); ) { FileSet set = (FileSet) i.next(); list.add( createDirectory( set ) ); } ScpToMessage message = new ScpToMessage( session, list, toValues[3] ); message.setLogListener( this ); message.execute(); } finally { if( session != null ) session.disconnect(); } } private void upload( String fromPath, String toSshUri ) throws IOException, JSchException { String[] toValues = parseUri(toSshUri); Session session = null; try { session = openSession( toValues[0], toValues[1], toValues[2], port ); ScpToMessage message = new ScpToMessage( session, new File( fromPath ), toValues[3] ); message.setLogListener( this ); message.execute(); } finally { if( session != null ) session.disconnect(); } } private Session openSession( String user, String password, String host, int port ) throws JSchException { JSch jsch = new JSch(); if( knownHosts != null ) { log( "Using known hosts: " + knownHosts, Project.MSG_DEBUG ); jsch.setKnownHosts( knownHosts ); } Session session = jsch.getSession( user, host, port ); UserInfo userInfo = new DefaultUserInfo( password, trust ); session.setUserInfo(userInfo); log("Connecting to " + host + ":" + port ); session.connect(); return session; } private String[] parseUri(String uri) { int indexOfAt = uri.indexOf('@'); int indexOfColon = uri.indexOf(':'); int indexOfPath = uri.indexOf(':', indexOfColon + 1); String[] values = new String[4]; values[0] = uri.substring(0, indexOfColon); values[1] = uri.substring(indexOfColon + 1, indexOfAt); values[2] = uri.substring(indexOfAt + 1, indexOfPath); values[3] = uri.substring(indexOfPath + 1); return values; } private boolean isRemoteUri(String uri) { boolean isRemote = true; int indexOfAt = uri.indexOf('@'); if (indexOfAt < 0) { isRemote = false; } return isRemote; } private Directory createDirectory( FileSet set ) { DirectoryScanner scanner = set.getDirectoryScanner( project ); Directory root = new Directory( scanner.getBasedir() ); String[] files = scanner.getIncludedFiles(); for (int j = 0; j < files.length; j++) { String[] path = Directory.getPath( files[j] ); Directory current = root; File currentParent = scanner.getBasedir(); for( int i = 0; i < path.length; i++ ) { File file = new File( currentParent, path[i] ); if( file.isDirectory() ) { current.addDirectory( new Directory( file ) ); current = current.getChild( file ); currentParent = current.getDirectory(); } else if( file.isFile() ) { current.addFile( file ); } } } return root; } public class DefaultUserInfo implements UserInfo { private String password = null; private boolean firstTime = true; private boolean trustAllCertificates; public DefaultUserInfo(String password, boolean trustAllCertificates) { this.password = password; this.trustAllCertificates = trustAllCertificates; } public String getPassphrase() { return null; } public String getPassword() { return password; } public boolean promptPassword( String passwordPrompt ) { log( passwordPrompt, Project.MSG_DEBUG ); if( firstTime ) { firstTime = false; return true; } return firstTime; } public boolean promptPassphrase( String passPhrasePrompt ) { return true; } public boolean promptYesNo( String prompt ) { log( prompt, Project.MSG_DEBUG ); return trustAllCertificates; } public void showMessage( String message ) { log( message, Project.MSG_DEBUG ); } } } 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java Index: ScpFromMessage.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.taskdefs.optional.ssh; import com.jcraft.jsch.*; import java.io.*; import java.util.StringTokenizer; import java.text.NumberFormat; public class ScpFromMessage extends AbstractSshMessage { private String remoteFile; private File localFile; private boolean isRecursive = false; public ScpFromMessage( Session session, String aRemoteFile, File aLocalFile, boolean recursive ) { super(session); this.remoteFile = aRemoteFile; this.localFile = aLocalFile; this.isRecursive = recursive; } public void execute() throws IOException { String command = "scp -f "; if( isRecursive ) command += "-r "; command += remoteFile; Channel channel = openExecChannel( command ); try { // get I/O streams for remote scp OutputStream out = channel.getOutputStream(); InputStream in = channel.getInputStream(); channel.connect(); sendAck(out); startRemoteCpProtocol( in, out, localFile); } finally { if( channel != null ) channel.disconnect(); } log( "done\n" ); } private void startRemoteCpProtocol(InputStream in, OutputStream out, File localFile) throws IOException { File startFile = localFile; while (true) { // C0644 filesize filename - header for a regular file // T time 0 time 0\n - present if perserve time. // D directory - this is the header for a directory. ByteArrayOutputStream stream = new ByteArrayOutputStream(); while( true ) { int read = in.read(); if( read < 0 ) return; if( (byte)read == (byte)0x0a ) break; stream.write( read ); } String serverResponse = stream.toString("UTF-8"); if( serverResponse.charAt(0) == 'C' ) { parseAndFetchFile( serverResponse, startFile, out, in ); } else if( serverResponse.charAt( 0 ) == 'D' ) { startFile = parseAndCreateDirectory( serverResponse, startFile ); sendAck( out ); } else if( serverResponse.charAt(0) == 'E' ) { startFile = startFile.getParentFile(); sendAck( out ); } else if( serverResponse.charAt( 0 ) == '\01' || serverResponse.charAt( 0 ) == '\02' ) { // this indicates an error. throw new IOException( serverResponse.substring(1) ); } } } private File parseAndCreateDirectory(String serverResponse, File localFile) { StringTokenizer token = new StringTokenizer( serverResponse ); String command = token.nextToken(); token.nextToken(); // appears that this is not used and it's zero. String directoryName = token.nextToken(); if( localFile.isDirectory() ) { File dir = new File( localFile, directoryName ); dir.mkdir(); return dir; } return null; } private void parseAndFetchFile(String serverResponse, File localFile, OutputStream out, InputStream in) throws IOException { StringTokenizer token = new StringTokenizer( serverResponse ); String command = token.nextToken(); int filesize = Integer.parseInt( token.nextToken() ); String filename = token.nextToken(); NumberFormat formatter = NumberFormat.getIntegerInstance(); log( "Receiving: " + filename + " : " + formatter.format( filesize ) ); File transferFile = ( localFile.isDirectory() ) ? new File( localFile, filename ) : localFile; fetchFile( transferFile, filesize, out, in); waitForAck(in); sendAck(out); } private void fetchFile( File localFile, int filesize, OutputStream out, InputStream in) throws IOException { byte[] buf = new byte[1024]; sendAck(out); // read a content of lfile FileOutputStream fos = new FileOutputStream( localFile ); int length; int totalLength = 0; long startTime = System.currentTimeMillis(); try { while (true) { length = in.read( buf, 0, (buf.length < filesize) ? buf.length : filesize ); if( length < 0 ) throw new EOFException("Unexpected end of stream."); fos.write( buf, 0, length ); filesize -= length; totalLength += length; if (filesize == 0) break; } } finally { long endTime = System.currentTimeMillis(); logStats( startTime, endTime, totalLength ); fos.flush(); fos.close(); } } } 1.1 ant/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java Index: ScpToMessage.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.taskdefs.optional.ssh; import com.jcraft.jsch.Session; import com.jcraft.jsch.Channel; import java.io.*; import java.util.*; import java.text.NumberFormat; public class ScpToMessage extends AbstractSshMessage { private File localFile; private String remotePath; private List directoryList; public ScpToMessage(Session session, File aLocalFile, String aRemotePath ) { super(session); this.localFile = aLocalFile; this.remotePath = aRemotePath; } public ScpToMessage( Session session, List aDirectoryList, String aRemotePath ) { super( session ); this.directoryList = aDirectoryList; this.remotePath = aRemotePath; } public void execute() throws IOException { if( directoryList != null ) { doMultipleTransfer(); } if( localFile != null ) { doSingleTransfer(); } log("done.\n"); } private void doSingleTransfer() throws IOException { String cmd = "scp -t " + remotePath; Channel channel = openExecChannel( cmd ); try { OutputStream out = channel.getOutputStream(); InputStream in = channel.getInputStream(); channel.connect(); waitForAck(in); sendFileToRemote(localFile, in, out); waitForAck(in); } finally { if( channel != null ) channel.disconnect(); } } private void doMultipleTransfer() throws IOException { Channel channel = openExecChannel( "scp -d -t " + remotePath ); try { OutputStream out = channel.getOutputStream(); InputStream in = channel.getInputStream(); channel.connect(); waitForAck(in); for( Iterator i = directoryList.iterator(); i.hasNext(); ) { Directory current = (Directory)i.next(); sendDirectory( current, in, out ); } waitForAck(in); } finally { if( channel != null ) channel.disconnect(); } } private void sendDirectory(Directory current, InputStream in, OutputStream out) throws IOException { for( Iterator fileIt = current.filesIterator(); fileIt.hasNext(); ) { sendFileToRemote( (File)fileIt.next(), in, out ); } for( Iterator dirIt = current.directoryIterator(); dirIt.hasNext(); ) { Directory dir = (Directory) dirIt.next(); sendDirectoryToRemote( dir, in ,out ); } } private void sendDirectoryToRemote( Directory directory, InputStream in, OutputStream out ) throws IOException { String command = "D0755 0 "; command += directory.getDirectory().getName(); command += "\n"; out.write( command.getBytes() ); out.flush(); waitForAck(in); sendDirectory( directory, in, out ); out.write( "E\n".getBytes() ); } private void sendFileToRemote( File localFile, InputStream in, OutputStream out ) throws IOException { // send "C0644 filesize filename", where filename should not include '/' int filesize = (int) localFile.length(); String command = "C0644 " + filesize + " "; command += localFile.getName(); command += "\n"; out.write( command.getBytes() ); out.flush(); waitForAck(in); // send a content of lfile FileInputStream fis = new FileInputStream(localFile); byte[] buf = new byte[1024]; long startTime = System.currentTimeMillis(); int totalLength = 0; try { NumberFormat formatter = NumberFormat.getIntegerInstance(); log( "Sending: " + localFile.getName() + " : " + formatter.format( localFile.length() ) ); while (true) { int len = fis.read(buf, 0, buf.length); if (len <= 0) break; out.write(buf, 0, len); totalLength += len; } out.flush(); sendAck(out); } finally { long endTime = System.currentTimeMillis(); logStats( startTime, endTime, totalLength ); fis.close(); } } public File getLocalFile() { return localFile; } public String getRemotePath() { return remotePath; } } 1.1 ant/src/testcases/org/apache/tools/ant/taskdefs/optional/ssh/ScpTest.java Index: ScpTest.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "Ant" and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.taskdefs.optional.ssh; import junit.framework.TestCase; import java.io.*; import java.util.List; import java.util.ArrayList; import java.util.Iterator; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.condition.FilesMatch; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.selectors.FilenameSelector; /** * This is a unit test for the Scp task in Ant. It must be * configured with command line options in order for it to work. * Here are the options: * * scp.tmp This is a local path to a temporary * directory for this task to use. * scp.host This is the remote location of the form: * "user:[EMAIL PROTECTED]:/path/to/directory" * scp.port The port of the listening SSH service. * Defaults to 22. (optional) * scp.known.hosts The file containing the public keys of known * hosts. Must be a SSH2 version file, but * supports RSA and DSA keys. If it is not present * this task setTrust() to true. (optional) */ public class ScpTest extends TestCase { private File tempDir = new File( System.getProperty("scp.tmp") ); private String sshHostUri = System.getProperty("scp.host"); private int port = Integer.parseInt( System.getProperty( "scp.port", "22" ) ); private String knownHosts = System.getProperty("scp.known.hosts"); private List cleanUpList = new ArrayList(); public ScpTest(String testname) { super(testname); } protected void setUp() { cleanUpList.clear(); } protected void tearDown() { for( Iterator i = cleanUpList.iterator(); i.hasNext(); ) { File file = (File) i.next(); file.delete(); } } public void testSingleFileUploadAndDownload() throws IOException { File uploadFile = createTemporaryFile(); Scp scpTask = createTask(); scpTask.setFile( uploadFile.getPath() ); scpTask.setTodir( sshHostUri ); scpTask.execute(); File testFile = new File( tempDir.getPath() + File.separator + "download-testSingleFileUploadAndDownload.test" ); addCleanup( testFile ); assertTrue( "Assert that the testFile does not exist.", !testFile.exists() ); scpTask.setFile( sshHostUri + "/" + uploadFile.getName() ); scpTask.setTodir( testFile.getPath() ); scpTask.execute(); assertTrue( "Assert that the testFile exists.", testFile.exists() ); compareFiles( uploadFile, testFile ); } public void testMultiUploadAndDownload() throws IOException { List uploadList = new ArrayList(); for( int i = 0; i < 5; i++ ) { uploadList.add( createTemporaryFile() ); } Scp scp = createTask(); FilenameSelector selector = new FilenameSelector(); selector.setName( "scp*" ); FileSet fileset = new FileSet(); fileset.setDir( tempDir ); fileset.addFilename( selector ); scp.addFileset( fileset ); scp.setTodir( sshHostUri ); scp.execute(); File multi = new File( tempDir, "multi" ); multi.mkdir(); addCleanup( multi ); Scp scp2 = createTask(); scp2.setFile( sshHostUri + "/scp*" ); scp2.setTodir( multi.getPath() ); scp2.execute(); FilesMatch match = new FilesMatch(); for( Iterator i = uploadList.iterator(); i.hasNext(); ) { File f = (File)i.next(); match.setFile1( f ); File f2 = new File( multi, f.getName() ); match.setFile2( f2 ); assertTrue("Assert file '" + f.getPath() + "' and file '" + f2.getPath() + "'", match.eval() ); } } public void addCleanup( File file ) { cleanUpList.add( file ); } private void compareFiles(File src, File dest) { FilesMatch match = new FilesMatch(); match.setFile1( src ); match.setFile2( dest ); assertTrue( "Assert files are equal.", match.eval() ); } private File createTemporaryFile() throws IOException { File uploadFile; uploadFile = File.createTempFile( "scp", "test", tempDir ); FileWriter writer = new FileWriter( uploadFile ); writer.write("Can you hear me now?\n"); writer.close(); addCleanup( uploadFile ); return uploadFile; } private Scp createTask() { Scp scp = new Scp(); Project p = new Project(); p.init(); scp.setProject( p ); if( knownHosts != null ) { scp.setKnownhosts( knownHosts ); } else { scp.setTrust( true ); } scp.setPort( port ); return scp; } }