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