Browse Source

New task <ftp> to do FTP _uploads_.

According to the information on the ORO inc website
<URL:http://www.oroinc.com>, the FTP library this task depends on will
be donated to the Jakarta project. This makes it our best choice among
several different FTP libraries, IMHO.

Submitted by:	Roger Vaughn <rvaughn@seaconinc.com>


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267895 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 25 years ago
parent
commit
3c66612026
5 changed files with 683 additions and 1 deletions
  1. +1
    -1
      WHATSNEW
  2. +2
    -0
      build.xml
  3. +144
    -0
      docs/index.html
  4. +1
    -0
      src/main/org/apache/tools/ant/taskdefs/defaults.properties
  5. +535
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/FTP.java

+ 1
- 1
WHATSNEW View File

@@ -20,7 +20,7 @@ org.apache.tools.ant to org.apache.tools.ant.types.
Other changes:
--------------

* New tasks: sql, genkey, cab.
* New tasks: sql, genkey, cab, ftp.

* New tasks junit, mparse, execon. All pending documentation, most of
them pending review.


+ 2
- 0
build.xml View File

@@ -50,6 +50,7 @@
<available property="ejb.DDCreator.present" classname="weblogic.ejb.utils.DDCreator" />
<available property="ejb.wls.present" classname="weblogic.Server" />
<available property="junit.present" classname="junit.framework.TestCase" />
<available property="ftp.present" classname="com.oroinc.net.ftp.FTPClient" />
</target>

<!-- =================================================================== -->
@@ -83,6 +84,7 @@
<exclude name="**/EjbJar.java" unless="jdk1.2+" />
<exclude name="**/*DeploymentTool.java" unless="jdk1.2+" />
<exclude name="**/junit/*" unless="junit.present" />
<exclude name="**/FTP*.java" unless="ftp.present" />
</javac>
<copydir src="${src.dir}" dest="${build.classes}">


+ 144
- 0
docs/index.html View File

@@ -21,6 +21,7 @@
<li>Conor MacNeill (<a href="mailto:conor@cortexebusiness.com.au">conor@cortexebusiness.com.au</a>)</li>
<li>Stefano Mazzocchi (<a href="mailto:stefano@apache.org">stefano@apache.org</a>)</li>
<li>Sam Ruby (<a href="mailto:rubys@us.ibm.com">rubys@us.ibm.com</a>)</li>
<li>Roger Vaughn (<a href="mailto:rvaughn@seaconinc.com">rvaughn@seaconinc.com</a>)</li>
<li>Dave Walend (<a href="mailto:dwalend@cs.tufts.edu">dwalend@cs.tufts.edu</a>)</li>
</ul>

@@ -3303,6 +3304,7 @@ and <code>todo.html</code> are excluded.</p>
<h2><a name="optionaltasks">Optional tasks</a></h2>
<ul>
<li><a href="#cab">Cab</a></li>
<li><a href="#ftp">FTP</a></li>
<li><a href="#netrexxc">NetRexxC</a></li>
<li><a href="#renameexts">RenameExtensions</a></li>
<li><a href="#script">Script</a></li>
@@ -3419,6 +3421,148 @@ directory api are archived, and files with the name todo.html are
excluded. Output from the cabarc tool is displayed in the build
output.</p>
<hr>
<h2><a name="ftp">FTP</a></h2>
<h3><b>Description:</b></h3>
<p>Copies files from the local system to a remote ftp server.</p>
<p>The <code>fileset</code> syntax must be used for specifying the local
files to copy. All filesets will be copied into the single remote directory
specified by <i>remotedir</i>.</p>
<p>The ftp task makes no attempt to determine what file system syntax is
required by the remote server, and defaults to Unix standards.
<i>remotedir</i> must be specified in the exact syntax required by the ftp
server. If the usual Unix conventions are not supported by the server,
<i>separator</i> can be used to set the file separator that should be used
instead.</p>
<p>See the section on <a href="#directorybasedtasks">directory based
tasks</a>, on how the inclusion/exclusion of files works, and how to
write patterns.</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">server</td>
<td valign="top">the address of the remote ftp server.</td>
<td valign="top" align="center">Yes</td>
</tr>
<tr>
<td valign="top">port</td>
<td valign="top">the port number of the remote ftp server.
Defaults to port 21.</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">userid</td>
<td valign="top">the login id to use on the ftp server.</td>
<td valign="top" align="center">Yes</td>
</tr>
<tr>
<td valign="top">password</td>
<td valign="top">the login password to use on the ftp server.</td>
<td valign="top" align="center">Yes</td>
</tr>
<tr>
<td valign="top">remotedir</td>
<td valign="top">the directory to which to upload files on the
ftp server.</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">action</td>
<td valign="top">the ftp action to perform.
Current only supports&quot;put&quot;</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">binary</td>
<td valign="top">selects binary-mode (&quot;yes&quot;) or text-mode
(&quot;no&quot;) transfers.
Defaults to &quot;yes&quot;</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">verbose</td>
<td valign="top">displays information on each file transferred if set
to &quot;yes&quot;. Defaults to &quot;no&quot;.</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">depends</td>
<td valign="top">transfers only new or changed files if set to
&quot;yes&quot;. Defaults to &quot;no&quot;.</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">newer</td>
<td valign="top">a synonym for <i>depends</i>.</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">separator</td>
<td valign="top">sets the file separator used on the ftp server.
Defaults to &quot;/&quot;.</td>
<td valign="top" align="center">No</td>
</tr>
</table>
<h3>Examples</h3>
<pre> &lt;ftp server=&quot;ftp.apache.org&quot;
userid=&quot;anonymous&quot;
password=&quot;me@myorg.com&quot;
&gt;
&lt;fileset dir=&quot;htdocs/manual&quot; /&gt;
&lt;/ftp&gt;</pre>
<p>Logs in to <code>ftp.apache.org</code> as <code>anonymous</code> and
uploads all files in the <code>htdocs/manual</code> directory
to the default directory for that user.</p>
<pre> &lt;ftp server=&quot;ftp.apache.org&quot;
remotedir=&quot;incoming&quot;
userid=&quot;anonymous&quot;
password=&quot;me@myorg.com&quot;
depends=&quot;yes&quot;
&gt;
&lt;fileset dir=&quot;htdocs/manual&quot; /&gt;
&lt;/ftp&gt;</pre>
<p>Logs in to <code>ftp.apache.org</code> as <code>anonymous</code> and
uploads all new or changed files in the <code>htdocs/manual</code> directory
to the <code>incoming</code> directory relative to the default directory
for <code>anonymous</code>.</p>
<pre> &lt;ftp server=&quot;ftp.apache.org&quot;
port=&quot;2121&quot;
remotedir=&quot;/pub/incoming&quot;
userid=&quot;coder&quot;
password=&quot;java1&quot;
depends=&quot;yes&quot;
binary=&quot;no&quot;
&gt;
&lt;fileset dir=&quot;htdocs/manual&quot;&gt;
&lt;include name=&quot;**/*.html&quot; /&gt;
&lt;/fileset&gt;
&lt;/ftp&gt;</pre>
<p>Logs in to <code>ftp.apache.org</code> at port <code>2121</code> as
<code>coder</code> with password <code>java1</code> and uploads all new or
changed HTML files in the <code>htdocs/manual</code> directory to the
<code>/pub/incoming</code> directory. The files are transferred in text
mode.</p>
<pre> &lt;ftp server=&quot;ftp.nt.org&quot;
remotedir=&quot;c:\uploads&quot;
userid=&quot;coder&quot;
password=&quot;java1&quot;
separator=&quot;\&quot;
verbose=&quot;yes&quot;
&gt;
&lt;fileset dir=&quot;htdocs/manual&quot;&gt;
&lt;include name=&quot;**/*.html&quot; /&gt;
&lt;/fileset&gt;
&lt;/ftp&gt;</pre>
<p>Logs in to the Windows-based <code>ftp.nt.org</code> as
<code>coder</code> with password <code>java1</code> and uploads all
HTML files in the <code>htdocs/manual</code> directory to the
<code>c:\uploads</code> directory. Progress messages are displayed as each
file is uploaded.</p>
<hr>
<h2><a name="netrexxc">NetRexxC</a></h2>
<h3><b>Description:</b></h3>
<p>Compiles a <a href="http://www2.hursley.ibm.com/netrexx">NetRexx</a>


+ 1
- 0
src/main/org/apache/tools/ant/taskdefs/defaults.properties View File

@@ -54,6 +54,7 @@ ejbjar=org.apache.tools.ant.taskdefs.optional.ejb.EjbJar
mparse=org.apache.tools.ant.taskdefs.optional.metamata.MParse
junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask
cab=org.apache.tools.ant.taskdefs.optional.Cab
ftp=org.apache.tools.ant.taskdefs.optional.FTP

# deprecated ant tasks (kept for back compatibility)
javadoc2=org.apache.tools.ant.taskdefs.Javadoc


+ 535
- 0
src/main/org/apache/tools/ant/taskdefs/optional/FTP.java View File

@@ -0,0 +1,535 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 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 "The Jakarta Project", "Tomcat", 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 apache@apache.org.
*
* 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;

import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;
import java.io.*;
import java.net.*;
import java.util.*;
import com.oroinc.net.ftp.*;

/**
* Sends files to an FTP server. Also intended to retrieve remote files,
* but this has not yet been implemented
*
* @author Roger Vaughn <a href="mailto:rvaughn@seaconinc.com">rvaughn@seaconinc.com</a>
*/
public class FTP
extends Task
{
protected final static int SEND_FILES = 0;
protected final static int GET_FILES = 1;
private String remotedir;
private String server;
private String userid;
private String password;
private boolean binary = true;
private boolean verbose = false;
private boolean newerOnly = false;
private int action = SEND_FILES;
private Vector filesets = new Vector();
private Vector dirCache = new Vector();
private int transferred = 0;
private String remoteFileSep = "/";
private int port = 21;

/**
* Sets the remote directory where files will be placed. This may
* be a relative or absolute path, and must be in the path syntax
* expected by the remote server. No correction of path syntax will
* be performed.
*/
public void setRemotedir(String dir)
{
this.remotedir = dir;
}

/**
* Sets the FTP server to send files to.
*/
public void setServer(String server)
{
this.server = server;
}

/**
* Sets the FTP port used by the remote server.
*/
public void setPort(int port)
{
this.port = port;
}

/**
* Sets the login user id to use on the specified server.
*/
public void setUserid(String userid)
{
this.userid = userid;
}

/**
* Sets the login password for the given user id.
*/
public void setPassword(String password)
{
this.password = password;
}

/**
* Specifies whether to use binary-mode or text-mode transfers. Set
* to true to send binary mode. Binary mode is enabled by default.
*/
public void setBinary(boolean binary)
{
this.binary = binary;
}

/**
* Set to true to receive notification about each file as it is
* transferred.
*/
public void setVerbose(boolean verbose)
{
this.verbose = verbose;
}

/**
* Set to true to transmit only files that are new or changed from their
* remote counterparts. The default is to transmit all files.
*/
public void setNewer(boolean newer)
{
this.newerOnly = newer;
}

/**
* A synonym for setNewer. Set to true to transmit only new or changed
* files.
*/
public void setDepends(boolean depends)
{
this.newerOnly = depends;
}

/**
* Sets the remote file separator character. This normally defaults to
* the Unix standard forward slash, but can be manually overridden using
* this call if the remote server requires some other separator. Only
* the first character of the string is used.
*/
public void setSeparator(String separator)
{
remoteFileSep = separator;
}

/**
* Adds a set of files (nested fileset attribute).
*/
public void addFileset(FileSet set) {
filesets.addElement(set);
}

/**
* Adds a reference to a set of files (nested filesetref element).
*/
public void addFilesetref(Reference ref) {
filesets.addElement(ref);
}

/**
* Sets the FTP action to be taken. Currently accepts "put" and "get".
* "get" tasks are not yet supported and will effectively perform a noop.
*/
public void setAction(String action) throws BuildException
{
if (action.toLowerCase().equals("send") ||
action.toLowerCase().equals("put"))
{
this.action = SEND_FILES;
}
else if (action.toLowerCase().equals("recv") ||
action.toLowerCase().equals("get"))
{
this.action = GET_FILES;
}
else
{
throw new BuildException("action " + action + " is not supported");
}
}

/**
* Checks to see that all required parameters are set.
*/
protected void checkConfiguration() throws BuildException
{
if (server == null)
{
throw new BuildException("server attribute must be set!");
}
if (userid == null)
{
throw new BuildException("userid attribute must be set!");
}
if (password == null)
{
throw new BuildException("password attribute must be set!");
}
}

/**
* Append all files found by a directory scanner to a vector.
*/
protected int sendFiles(FTPClient ftp, DirectoryScanner ds)
throws IOException, BuildException
{
String[] dsfiles = ds.getIncludedFiles();
String dir = ds.getBasedir().getAbsolutePath();

for (int i = 0; i < dsfiles.length; i++)
{
sendFile(ftp, dir, dsfiles[i]);
}

return dsfiles.length;
}

/**
* Sends all files specified by the configured filesets to the remote
* server.
*/
protected void sendFiles(FTPClient ftp)
throws IOException, BuildException
{
transferred = 0;
if (filesets.size() == 0)
{
throw new BuildException("at least one fileset must be specified.");
}
else
{
// get files from filesets
for (int i = 0; i < filesets.size(); i++)
{
Object o = filesets.elementAt(i);
FileSet fs;
if (o instanceof FileSet)
{
fs = (FileSet)o;
}
else if (o instanceof Reference)
{
Reference r = (Reference)o;
o = r.getReferencedObject(project);

if (o instanceof FileSet)
{
fs = (FileSet)o;
}
else
{
throw new BuildException(
r.getRefId() + " does not denote a fileset",
location);
}
}
else
{
throw new BuildException(
"nested element is not a FileSet or Reference",
location);
}

if (fs != null)
{
sendFiles(ftp, fs.getDirectoryScanner(project));
}
}
}

log(transferred + " files transferred");
}

/**
* Correct a file path to correspond to the remote host requirements.
* This implementation currently assumes that the remote end can
* handle Unix-style paths with forward-slash separators. This can
* be overridden with the <code>separator</code> task parameter. No
* attempt is made to determine what syntax is appropriate for the
* remote host.
*/
protected String resolveFile(String file)
{
return file.replace(System.getProperty("file.separator").charAt(0),
remoteFileSep.charAt(0));
}

/**
* Creates all parent directories specified in a complete relative
* pathname. Attempts to create existing directories will not cause
* errors.
*/
protected void createParents(FTPClient ftp, String filename)
throws IOException, BuildException
{
Vector parents = new Vector();
File dir = new File(filename);
String dirname;

while ((dirname = dir.getParent()) != null)
{
dir = new File(dirname);
parents.addElement(dir);
}

for (int i = parents.size() - 1; i >= 0; i--)
{
dir = (File)parents.elementAt(i);
if (!dirCache.contains(dir))
{
log("creating remote directory " + resolveFile(dir.getPath()),
Project.MSG_VERBOSE);
ftp.makeDirectory(resolveFile(dir.getPath()));
if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()) &&
(ftp.getReplyCode() != 550))
{
throw new BuildException(
"could not create directory: " +
ftp.getReplyString());
}
dirCache.addElement(dir);
}
}
}

/**
* Checks to see if the remote file is current as compared with the
* local file. Returns true if the remote file is up to date.
*/
protected boolean isUpToDate(FTPClient ftp, File localFile, String remoteFile)
throws IOException, BuildException
{
log("checking date for " + remoteFile, Project.MSG_VERBOSE);
FTPFile[] files = ftp.listFiles(remoteFile);
if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
{
throw new BuildException(
"could not date test remote file: " +
ftp.getReplyString());
}

if (files == null)
{
return false;
}

return files[0].getTimestamp().getTime().getTime() >
localFile.lastModified();
}

/**
* Sends a single file to the remote host.
* <code>filename</code> may contain a relative path specification.
* When this is the case, <code>sendFile</code> will attempt to create
* any necessary parent directories before sending the file. The file
* will then be sent using the entire relative path spec - no attempt
* is made to change directories. It is anticipated that this may
* eventually cause problems with some FTP servers, but it simplifies
* the coding.
*/
protected void sendFile(FTPClient ftp, String dir, String filename)
throws IOException, BuildException
{
InputStream instream = null;
try
{
File file = project.resolveFile(new File(dir, filename).getPath());

if (newerOnly && isUpToDate(ftp, file, resolveFile(filename)))
return;

if (verbose)
{
log("transferring " + file.getAbsolutePath());
}
instream = new BufferedInputStream(new FileInputStream(file));
createParents(ftp, filename);
ftp.storeFile(resolveFile(filename), instream);
if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
{
throw new BuildException(
"could not transfer file: " +
ftp.getReplyString());
}
log("File " + file.getAbsolutePath() + " copied to " + server,
Project.MSG_VERBOSE);

transferred++;
}
finally
{
if (instream != null)
{
try
{
instream.close();
}
catch(IOException ex)
{
// ignore it
}
}
}
}

/**
* Runs the task.
*/
public void execute()
throws BuildException
{
checkConfiguration();
FTPClient ftp = null;

try
{
log("Opening FTP connection to " + server, Project.MSG_VERBOSE);

ftp = new FTPClient();
ftp.connect(server, port);
if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
{
throw new BuildException("FTP connection failed: " + ftp.getReplyString());
}

log("connected", Project.MSG_VERBOSE);
log("logging in to FTP server", Project.MSG_VERBOSE);

if (!ftp.login(userid, password))
{
throw new BuildException("Could not login to FTP server");
}

log("login succeeded", Project.MSG_VERBOSE);
if (binary)
{
ftp.setFileType(com.oroinc.net.ftp.FTP.IMAGE_FILE_TYPE);
if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
{
throw new BuildException(
"could not set transfer type: " +
ftp.getReplyString());
}
}

if (remotedir != null)
{
log("changing the remote directory", Project.MSG_VERBOSE);
ftp.changeWorkingDirectory(remotedir);
if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
{
throw new BuildException(
"could not change remote directory: " +
ftp.getReplyString());
}
}

log("transferring files");

if (action == SEND_FILES)
{
sendFiles(ftp);
}
else
{
throw new BuildException("getting files is not yet supported");
}
}
catch(IOException ex)
{
throw new BuildException("error during FTP transfer: " + ex);
}
finally
{
/*
if (ftp != null && ftp.isConnected())
{
try
{
// this hangs - I don't know why.
ftp.disconnect();
}
catch(IOException ex)
{
// ignore it
}
}
*/
}
}
}

Loading…
Cancel
Save