Author: bodewig Date: Mon May 8 21:26:36 2006 New Revision: 405300 URL: http://svn.apache.org/viewcvs?rev=405300&view=rev Log: Make <scp> support the sftp protocol. PR 39373
Added: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java (with props) ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java (with props) Modified: ant/core/trunk/WHATSNEW ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java Modified: ant/core/trunk/WHATSNEW URL: http://svn.apache.org/viewcvs/ant/core/trunk/WHATSNEW?rev=405300&r1=405299&r2=405300&view=diff ============================================================================== --- ant/core/trunk/WHATSNEW (original) +++ ant/core/trunk/WHATSNEW Mon May 8 21:26:36 2006 @@ -410,6 +410,8 @@ * Handling of ' ', '#' in CLASSPATH and '#' in -lib (cannot use ' ' in -lib on UNIX at the moment). Bugzilla Report 39295. +* <scp> now optionally supports the sftp protocol. Bugzilla Report 39373. + Changes from Ant 1.6.4 to Ant 1.6.5 =================================== Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java?rev=405300&r1=405299&r2=405300&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java Mon May 8 21:26:36 2006 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 The Apache Software Foundation + * Copyright 2003-2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,10 @@ import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.SftpATTRS; +import com.jcraft.jsch.SftpException; +import com.jcraft.jsch.SftpProgressMonitor; import java.io.IOException; import java.io.OutputStream; @@ -75,6 +79,17 @@ } /** + * Open an ssh sftp channel. + * @return the channel + * @throws JSchException on error + */ + protected ChannelSftp openSftpChannel() throws JSchException { + ChannelSftp channel = (ChannelSftp) session.openChannel("sftp"); + + return channel; + } + + /** * Send an ack. * @param out the output stream to use * @throws IOException on error @@ -213,4 +228,39 @@ return percent; } + private ProgressMonitor monitor = null; + + protected SftpProgressMonitor getProgressMonitor(){ + if (monitor == null) { + monitor = new ProgressMonitor(); + } + return monitor; + } + + private class ProgressMonitor implements SftpProgressMonitor { + private long initFileSize = 0; + private long totalLength = 0; + private int percentTransmitted = 0; + + public void init(int op, String src, String dest, long max) { + initFileSize = max; + totalLength = 0; + percentTransmitted = 0; + } + + public boolean count(long len) { + totalLength += len; + percentTransmitted = trackProgress(initFileSize, + totalLength, + percentTransmitted); + return true; + } + + public void end() { + } + + public long getTotalLength() { + return totalLength; + } + } } Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java?rev=405300&r1=405299&r2=405300&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java Mon May 8 21:26:36 2006 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 The Apache Software Foundation + * Copyright 2003-2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,6 +44,7 @@ private String toUri; private List fileSets = null; private boolean isFromRemote, isToRemote; + private boolean isSftp = false; /** * Sets the file to be transferred. This can either be a remote @@ -142,6 +143,15 @@ } /** + * Setting this to true to use sftp protocol. + * + * @param yesOrNo if true sftp protocol will be used. + */ + public void setSftp(boolean yesOrNo) { + isSftp = yesOrNo; + } + + /** * Adds a FileSet tranfer to remote host. NOTE: Either * addFileSet() or setFile() are required. But, not both. * @@ -213,10 +223,18 @@ Session session = null; try { session = openSession(); - ScpFromMessage message = - new ScpFromMessage(getVerbose(), session, file, - getProject().resolveFile(toPath), - fromSshUri.endsWith("*")); + ScpFromMessage message = null; + if (!isSftp){ + message = + new ScpFromMessage(getVerbose(), session, file, + getProject().resolveFile(toPath), + fromSshUri.endsWith("*")); + } else{ + message = + new ScpFromMessageBySftp(getVerbose(), session, file, + getProject().resolveFile(toPath), + fromSshUri.endsWith("*")); + } log("Receiving file: " + file); message.setLogListener(this); message.execute(); @@ -243,8 +261,14 @@ } if (!list.isEmpty()) { session = openSession(); - ScpToMessage message = new ScpToMessage(getVerbose(), session, - list, file); + ScpToMessage message = null; + if (!isSftp){ + message = new ScpToMessage(getVerbose(), session, + list, file); + } else{ + message = new ScpToMessageBySftp(getVerbose(), session, + list, file); + } message.setLogListener(this); message.execute(); } @@ -262,9 +286,17 @@ Session session = null; try { session = openSession(); - ScpToMessage message = - new ScpToMessage(getVerbose(), session, - getProject().resolveFile(fromPath), file); + ScpToMessage message = null; + if (!isSftp){ + message = + new ScpToMessage(getVerbose(), session, + getProject().resolveFile(fromPath), file); + } else{ + message = + new ScpToMessageBySftp(getVerbose(), session, + getProject().resolveFile(fromPath), + file); + } message.setLogListener(this); message.execute(); } finally { Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java?rev=405300&r1=405299&r2=405300&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java Mon May 8 21:26:36 2006 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 The Apache Software Foundation + * Copyright 2003-2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,24 @@ private String remoteFile; private File localFile; private boolean isRecursive = false; + + /** + * Constructor for ScpFromMessage + * @param session the ssh session to use + */ + public ScpFromMessage(Session session) { + super(session); + } + + /** + * Constructor for ScpFromMessage + * @param verbose if true do verbose logging + * @param session the ssh session to use + * @since Ant 1.6.2 + */ + public ScpFromMessage(boolean verbose, Session session) { + super(verbose, session); + } /** * Constructor for ScpFromMessage. Added: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java?rev=405300&view=auto ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java (added) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java Mon May 8 21:26:36 2006 @@ -0,0 +1,173 @@ +/* + * Copyright 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.tools.ant.taskdefs.optional.ssh; + +import java.io.File; +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.ByteArrayOutputStream; + +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.Channel; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.SftpException; +import com.jcraft.jsch.SftpATTRS; +import com.jcraft.jsch.SftpProgressMonitor; + +/** + * A helper object representing an scp download. + */ +public class ScpFromMessageBySftp extends ScpFromMessage { + + private String remoteFile; + private File localFile; + private boolean isRecursive = false; + private boolean verbose = false; + + /** + * Constructor for ScpFromMessageBySftp. + * @param verbose if true log extra information + * @param session the Scp session to use + * @param aRemoteFile the remote file name + * @param aLocalFile the local file + * @param recursive if true use recursion + * @since Ant 1.7 + */ + public ScpFromMessageBySftp(boolean verbose, + Session session, + String aRemoteFile, + File aLocalFile, + boolean recursive) { + super(verbose, session); + this.verbose = verbose; + this.remoteFile = aRemoteFile; + this.localFile = aLocalFile; + this.isRecursive = recursive; + } + + /** + * Constructor for ScpFromMessageBySftp. + * @param session the Scp session to use + * @param aRemoteFile the remote file name + * @param aLocalFile the local file + * @param recursive if true use recursion + */ + public ScpFromMessageBySftp(Session session, + String aRemoteFile, + File aLocalFile, + boolean recursive) { + this(false, session, aRemoteFile, aLocalFile, recursive); + } + + /** + * Carry out the transfer. + * @throws IOException on i/o errors + * @throws JSchException on errors detected by scp + */ + public void execute() throws IOException, JSchException { + ChannelSftp channel = openSftpChannel(); + try { + channel.connect(); + try { + SftpATTRS attrs = channel.stat(remoteFile); + if (attrs.isDir() && !remoteFile.endsWith("/")) { + remoteFile=remoteFile+"/"; + } + } catch(SftpException ee) { + } + getDir(channel, remoteFile, localFile); + } catch(SftpException e) { + throw new JSchException(e.toString()); + } finally { + if (channel != null) { + channel.disconnect(); + } + } + log("done\n"); + } + + private void getDir(ChannelSftp channel, + String remoteFile, + File localFile) throws IOException, SftpException { + String pwd=remoteFile; + if (remoteFile.lastIndexOf('/')!=-1) { + if (remoteFile.length()>1) { + pwd=remoteFile.substring(0, remoteFile.lastIndexOf('/')); + } + } + channel.cd(pwd); + if (!localFile.exists()) { + localFile.mkdirs(); + } + java.util.Vector files = channel.ls(remoteFile); + for(int i = 0; i < files.size(); i++){ + ChannelSftp.LsEntry le = (ChannelSftp.LsEntry) files.elementAt(i); + String name = le.getFilename(); + if (le.getAttrs().isDir()) { + if (name.equals(".") || name.equals("..")) { + continue; + } + getDir(channel, + channel.pwd() + "/" + name + "/", + new File(localFile, le.getFilename())); + } else{ + getFile(channel, le, localFile); + } + } + channel.cd(".."); + } + + private void getFile(ChannelSftp channel, + ChannelSftp.LsEntry le, + File localFile) throws IOException, SftpException { + String remoteFile = le.getFilename(); + if (!localFile.exists()) { + String path = localFile.getAbsolutePath(); + int i = 0; + if ((i = path.lastIndexOf(File.pathSeparator)) != -1) { + if (path.length()>File.pathSeparator.length()) { + new File(path.substring(0, i)).mkdirs(); + } + } + } + + if (localFile.isDirectory()) { + localFile=new File(localFile, remoteFile); + } + + long startTime = System.currentTimeMillis(); + long totalLength = le.getAttrs().getSize(); + + SftpProgressMonitor monitor = null; + boolean trackProgress = getVerbose() && totalLength > 102400; + if (trackProgress){ + monitor = getProgressMonitor(); + } + try{ + log("Receiving: " + remoteFile + " : " + le.getAttrs().getSize()); + channel.get(remoteFile, localFile.getAbsolutePath(), monitor); + } finally{ + long endTime = System.currentTimeMillis(); + logStats(startTime, endTime, (int)totalLength); + } + } +} Propchange: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java?rev=405300&r1=405299&r2=405300&view=diff ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java (original) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java Mon May 8 21:26:36 2006 @@ -40,6 +40,24 @@ private List directoryList; /** + * Constructor for ScpToMessage + * @param session the ssh session to use + */ + public ScpToMessage(Session session) { + super(session); + } + + /** + * Constructor for ScpToMessage + * @param verbose if true do verbose logging + * @param session the ssh session to use + * @since Ant 1.7 + */ + public ScpToMessage(boolean verbose, Session session) { + super(verbose, session); + } + + /** * Constructor for a local file to remote. * @param verbose if true do verbose logging * @param session the scp session to use Added: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java URL: http://svn.apache.org/viewcvs/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java?rev=405300&view=auto ============================================================================== --- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java (added) +++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java Mon May 8 21:26:36 2006 @@ -0,0 +1,240 @@ +/* + * Copyright 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.tools.ant.taskdefs.optional.ssh; + +import com.jcraft.jsch.Channel; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.SftpException; +import com.jcraft.jsch.SftpProgressMonitor; +import com.jcraft.jsch.SftpATTRS; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.Iterator; + +public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { + + private File localFile; + private String remotePath; + private List directoryList; + + /** + * Constructor for a local file to remote. + * @param verbose if true do verbose logging + * @param session the scp session to use + * @param aLocalFile the local file + * @param aRemotePath the remote path + * @since Ant 1.7 + */ + public ScpToMessageBySftp(boolean verbose, + Session session, + File aLocalFile, + String aRemotePath) { + this(verbose, session, aRemotePath); + + this.localFile = aLocalFile; + } + + /** + * Constructor for a local directories to remote. + * @param verbose if true do verbose logging + * @param session the scp session to use + * @param aDirectoryList a list of directories + * @param aRemotePath the remote path + * @since Ant 1.7 + */ + public ScpToMessageBySftp(boolean verbose, + Session session, + List aDirectoryList, + String aRemotePath) { + this(verbose, session, aRemotePath); + + this.directoryList = aDirectoryList; + } + + /** + * Constructor for ScpToMessage. + * @param verbose if true do verbose logging + * @param session the scp session to use + * @param aRemotePath the remote path + * @since Ant 1.6.2 + */ + private ScpToMessageBySftp(boolean verbose, + Session session, + String aRemotePath) { + super(verbose, session); + this.remotePath = aRemotePath; + } + + /** + * Constructor for ScpToMessage. + * @param session the scp session to use + * @param aLocalFile the local file + * @param aRemotePath the remote path + */ + public ScpToMessageBySftp(Session session, + File aLocalFile, + String aRemotePath) { + this(false, session, aLocalFile, aRemotePath); + } + + /** + * Constructor for ScpToMessage. + * @param session the scp session to use + * @param aDirectoryList a list of directories + * @param aRemotePath the remote path + */ + public ScpToMessageBySftp(Session session, + List aDirectoryList, + String aRemotePath) { + this(false, session, aDirectoryList, aRemotePath); + } + + /** + * Carry out the transfer. + * @throws IOException on i/o errors + * @throws JSchException on errors detected by scp + */ + public void execute() throws IOException, JSchException { + if (directoryList != null) { + doMultipleTransfer(); + } + if (localFile != null) { + doSingleTransfer(); + } + log("done.\n"); + } + + private void doSingleTransfer() throws IOException, JSchException { + ChannelSftp channel = openSftpChannel(); + try { + channel.connect(); + try{ + sendFileToRemote(channel, localFile, remotePath); + } + catch(SftpException e){ + throw new JSchException(e.toString()); + } + } finally { + if (channel != null) { + channel.disconnect(); + } + } + } + + private void doMultipleTransfer() throws IOException, JSchException { + ChannelSftp channel = openSftpChannel(); + try { + channel.connect(); + + try{ + channel.cd(remotePath); + for (Iterator i = directoryList.iterator(); i.hasNext();) { + Directory current = (Directory) i.next(); + sendDirectory(channel, current); + } + } + catch(SftpException e){ + throw new JSchException(e.toString()); + } + } finally { + if (channel != null) { + channel.disconnect(); + } + } + } + + private void sendDirectory(ChannelSftp channel, + Directory current) + throws IOException, SftpException { + for (Iterator fileIt = current.filesIterator(); fileIt.hasNext();) { + sendFileToRemote(channel, (File) fileIt.next(), null); + } + for (Iterator dirIt = current.directoryIterator(); dirIt.hasNext();) { + Directory dir = (Directory) dirIt.next(); + sendDirectoryToRemote(channel, dir); + } + } + + private void sendDirectoryToRemote(ChannelSftp channel, + Directory directory) + throws IOException, SftpException { + String dir=directory.getDirectory().getName(); + try{ + channel.stat(dir); + } + catch(SftpException e){ + // dir does not exist. + if (e.id==ChannelSftp.SSH_FX_NO_SUCH_FILE) { + channel.mkdir(dir); + } + } + channel.cd(dir); + sendDirectory(channel, directory); + channel.cd(".."); + } + + private void sendFileToRemote(ChannelSftp channel, + File localFile, + String remotePath) + throws IOException, SftpException { + long filesize = localFile.length(); + + if (remotePath==null) { + remotePath=localFile.getName(); + } + + long startTime = System.currentTimeMillis(); + long totalLength = filesize; + + // only track progress for files larger than 100kb in verbose mode + boolean trackProgress = getVerbose() && filesize > 102400; + + SftpProgressMonitor monitor = null; + if (trackProgress){ + monitor = getProgressMonitor(); + } + + try{ + if (this.getVerbose()) { + log("Sending: " + localFile.getName() + " : " + filesize); + } + channel.put(localFile.getAbsolutePath(), remotePath, monitor); + } + finally { + if (this.getVerbose()) { + long endTime = System.currentTimeMillis(); + logStats(startTime, endTime, (int) totalLength); + } + } + } + + public File getLocalFile() { + return localFile; + } + + public String getRemotePath() { + return remotePath; + } +} Propchange: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]