diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java new file mode 100644 index 00000000..46e2ac64 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java @@ -0,0 +1,486 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +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; + +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +/** + * Ant task for sending files to remote machine over ssh/scp. + * + * @since Ant 1.6 + */ +public class Scp extends SSHBase { + + private static final String[] FROM_ATTRS = { + "file", "localfile", "remotefile" }; + + private static final String[] TO_ATTRS = { + "todir", "localtodir", "remotetodir", "localtofile", "remotetofile" }; + + private String fromUri; + private String toUri; + private boolean preserveLastModified = false; + private List fileSets = null; + private boolean isFromRemote, isToRemote; + private boolean isSftp = false; + private Integer fileMode, dirMode; + + /** + * 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:password@host:/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:password@host:/directory/path/*</i><br> + * @param aFromUri a string representing the file to transfer. + */ + public void setFile(final String aFromUri) { + setFromUri(aFromUri); + this.isFromRemote = isRemoteUri(this.fromUri); + } + + /** + * 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:password@host:/directory/path/</i><br> + * This parameter is required. + + * @param aToUri a string representing the target of the copy. + */ + public void setTodir(final String aToUri) { + setToUri(aToUri); + this.isToRemote = isRemoteUri(this.toUri); + } + + /** + * Similar to {@link #setFile setFile} but explicitly states that + * the file is a local file. This is the only way to specify a + * local file with a @ character. + * @param aFromUri a string representing the source of the copy. + * @since Ant 1.6.2 + */ + public void setLocalFile(final String aFromUri) { + setFromUri(aFromUri); + this.isFromRemote = false; + } + + /** + * Similar to {@link #setFile setFile} but explicitly states that + * the file is a remote file. + * @param aFromUri a string representing the source of the copy. + * @since Ant 1.6.2 + */ + public void setRemoteFile(final String aFromUri) { + validateRemoteUri("remoteFile", aFromUri); + setFromUri(aFromUri); + this.isFromRemote = true; + } + + /** + * Similar to {@link #setTodir setTodir} but explicitly states + * that the directory is a local. This is the only way to specify + * a local directory with a @ character. + * @param aToUri a string representing the target of the copy. + * @since Ant 1.6.2 + */ + public void setLocalTodir(final String aToUri) { + setToUri(aToUri); + this.isToRemote = false; + } + + /** + * Sets flag to determine if file timestamp from + * remote system is to be preserved during copy. + * @since Ant 1.8.0 + */ + public void setPreservelastmodified(final boolean yesOrNo) { + this.preserveLastModified = yesOrNo; + } + + /** + * Similar to {@link #setTodir setTodir} but explicitly states + * that the directory is a remote. + * @param aToUri a string representing the target of the copy. + * @since Ant 1.6.2 + */ + public void setRemoteTodir(final String aToUri) { + validateRemoteUri("remoteToDir", aToUri); + setToUri(aToUri); + this.isToRemote = true; + } + + private static void validateRemoteUri(final String type, final String aToUri) { + if (!isRemoteUri(aToUri)) { + throw new BuildException(type + " '" + aToUri + "' is invalid. " + + "The 'remoteToDir' attribute must " + + "have syntax like the " + + "following: user:password@host:/path" + + " - the :password part is optional"); + } + } + + /** + * Changes the file name to the given name while receiving it, + * only useful if receiving a single file. + * @param aToUri a string representing the target of the copy. + * @since Ant 1.6.2 + */ + public void setLocalTofile(final String aToUri) { + setToUri(aToUri); + this.isToRemote = false; + } + + /** + * Changes the file name to the given name while sending it, + * only useful if sending a single file. + * @param aToUri a string representing the target of the copy. + * @since Ant 1.6.2 + */ + public void setRemoteTofile(final String aToUri) { + validateRemoteUri("remoteToFile", aToUri); + setToUri(aToUri); + this.isToRemote = true; + } + + /** + * Setting this to true to use sftp protocol. + * + * @param yesOrNo if true sftp protocol will be used. + */ + public void setSftp(final boolean yesOrNo) { + isSftp = yesOrNo; + } + + /** + * Set the file mode, defaults to "644". + * @since Ant 1.9.5 + */ + public void setFileMode(String fileMode) { + this.fileMode = Integer.parseInt(fileMode, 8); + } + + /** + * Set the dir mode, defaults to "755". + * @since Ant 1.9.5 + */ + public void setDirMode(String dirMode) { + this.dirMode = Integer.parseInt(dirMode, 8); + } + + /** + * Adds a FileSet transfer to remote host. NOTE: Either + * addFileSet() or setFile() are required. But, not both. + * + * @param set FileSet to send to remote host. + */ + public void addFileset(final FileSet set) { + if (fileSets == null) { + fileSets = new LinkedList(); + } + fileSets.add(set); + } + + /** + * Initialize this task. + * @throws BuildException on error + */ + @Override + public void init() throws BuildException { + super.init(); + this.toUri = null; + this.fromUri = null; + this.fileSets = null; + } + + /** + * Execute this task. + * @throws BuildException on error + */ + @Override + public void execute() throws BuildException { + if (toUri == null) { + throw exactlyOne(TO_ATTRS); + } + if (fromUri == null && fileSets == null) { + throw exactlyOne(FROM_ATTRS, "one or more nested filesets"); + } + 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) { + throw new BuildException( + "Copying from a remote server to a remote server is not supported."); + } else { + throw new BuildException("'todir' and 'file' attributes " + + "must have syntax like the following: " + + "user:password@host:/path"); + } + } catch (final Exception e) { + if (getFailonerror()) { + if(e instanceof BuildException) { + final BuildException be = (BuildException) e; + if(be.getLocation() == null) { + be.setLocation(getLocation()); + } + throw be; + } else { + throw new BuildException(e); + } + } else { + log("Caught exception: " + e.getMessage(), Project.MSG_ERR); + } + } + } + + private void download(final String fromSshUri, final String toPath) + throws JSchException, IOException { + final String file = parseUri(fromSshUri); + + Session session = null; + try { + session = openSession(); + ScpFromMessage message = null; + if (!isSftp) { + message = + new ScpFromMessage(getVerbose(), session, file, + getProject().resolveFile(toPath), + fromSshUri.endsWith("*"), + preserveLastModified); + } else { + message = + new ScpFromMessageBySftp(getVerbose(), session, file, + getProject().resolveFile(toPath), + fromSshUri.endsWith("*"), + preserveLastModified); + } + log("Receiving file: " + file); + message.setLogListener(this); + message.execute(); + } finally { + if (session != null) { + session.disconnect(); + } + } + } + + private void upload(final List fileSet, final String toSshUri) + throws IOException, JSchException { + final String file = parseUri(toSshUri); + + Session session = null; + try { + final List list = new ArrayList(fileSet.size()); + for (final Iterator i = fileSet.iterator(); i.hasNext();) { + final FileSet set = (FileSet) i.next(); + final Directory d = createDirectory(set); + if (d != null) { + list.add(d); + } + } + if (!list.isEmpty()) { + session = openSession(); + ScpToMessage message = null; + if (!isSftp) { + message = new ScpToMessage(getVerbose(), session, + list, file); + } else { + message = new ScpToMessageBySftp(getVerbose(), session, + list, file); + } + message.setLogListener(this); + if (fileMode != null) { + message.setFileMode(fileMode.intValue()); + } + if (dirMode != null) { + message.setDirMode(dirMode.intValue()); + } + message.execute(); + } + } finally { + if (session != null) { + session.disconnect(); + } + } + } + + private void upload(final String fromPath, final String toSshUri) + throws IOException, JSchException { + final String file = parseUri(toSshUri); + + Session session = null; + try { + session = openSession(); + 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); + if (fileMode != null) { + message.setFileMode(fileMode.intValue()); + } + if (dirMode != null) { + message.setDirMode(dirMode.intValue()); + } + message.execute(); + } finally { + if (session != null) { + session.disconnect(); + } + } + } + + private String parseUri(final String uri) { + + int indexOfAt = uri.indexOf('@'); + final int indexOfColon = uri.indexOf(':'); + + if (indexOfColon > -1 && indexOfColon < indexOfAt) { + // user:password@host:/path notation + // everything upto the last @ before the last : is considered + // password. (so if the path contains an @ and a : it will not work) + int indexOfCurrentAt = indexOfAt; + final int indexOfLastColon = uri.lastIndexOf(':'); + while (indexOfCurrentAt > -1 && indexOfCurrentAt < indexOfLastColon) + { + indexOfAt = indexOfCurrentAt; + indexOfCurrentAt = uri.indexOf('@', indexOfCurrentAt + 1); + } + setUsername(uri.substring(0, indexOfColon)); + setPassword(uri.substring(indexOfColon + 1, indexOfAt)); + } else if (indexOfAt > -1) { + // no password, will require keyfile + setUsername(uri.substring(0, indexOfAt)); + } else { + throw new BuildException("no username was given. Can't authenticate."); + } + + if (getUserInfo().getPassword() == null + && getUserInfo().getKeyfile() == null) { + throw new BuildException("neither password nor keyfile for user " + + getUserInfo().getName() + " has been " + + "given. Can't authenticate."); + } + + final int indexOfPath = uri.indexOf(':', indexOfAt + 1); + if (indexOfPath == -1) { + throw new BuildException("no remote path in " + uri); + } + + setHost(uri.substring(indexOfAt + 1, indexOfPath)); + String remotePath = uri.substring(indexOfPath + 1); + if (remotePath.equals("")) { + remotePath = "."; + } + return remotePath; + } + + private static boolean isRemoteUri(final String uri) { + boolean isRemote = true; + final int indexOfAt = uri.indexOf('@'); + if (indexOfAt < 0) { + isRemote = false; + } + return isRemote; + } + + private Directory createDirectory(final FileSet set) { + final DirectoryScanner scanner = set.getDirectoryScanner(getProject()); + Directory root = new Directory(scanner.getBasedir()); + final String[] files = scanner.getIncludedFiles(); + if (files.length != 0) { + for (int j = 0; j < files.length; j++) { + final String[] path = Directory.getPath(files[j]); + Directory current = root; + File currentParent = scanner.getBasedir(); + for (int i = 0; i < path.length; i++) { + final 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); + } + } + } + } else { + // skip + root = null; + } + return root; + } + + private void setFromUri(final String fromUri) { + if (this.fromUri != null) { + throw exactlyOne(FROM_ATTRS); + } + this.fromUri = fromUri; + } + + private void setToUri(final String toUri) { + if (this.toUri != null) { + throw exactlyOne(TO_ATTRS); + } + this.toUri = toUri; + } + + private BuildException exactlyOne(final String[] attrs) { + return exactlyOne(attrs, null); + } + + private BuildException exactlyOne(final String[] attrs, final String alt) { + final StringBuffer buf = new StringBuffer("Exactly one of ").append( + '[').append(attrs[0]); + for (int i = 1; i < attrs.length; i++) { + buf.append('|').append(attrs[i]); + } + buf.append(']'); + if (alt != null) { + buf.append(" or ").append(alt); + } + return new BuildException(buf.append(" is required.").toString()); + } +} |