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: Other changes:
-------------- --------------


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


* New tasks junit, mparse, execon. All pending documentation, most of * New tasks junit, mparse, execon. All pending documentation, most of
them pending review. 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.DDCreator.present" classname="weblogic.ejb.utils.DDCreator" />
<available property="ejb.wls.present" classname="weblogic.Server" /> <available property="ejb.wls.present" classname="weblogic.Server" />
<available property="junit.present" classname="junit.framework.TestCase" /> <available property="junit.present" classname="junit.framework.TestCase" />
<available property="ftp.present" classname="com.oroinc.net.ftp.FTPClient" />
</target> </target>


<!-- =================================================================== --> <!-- =================================================================== -->
@@ -83,6 +84,7 @@
<exclude name="**/EjbJar.java" unless="jdk1.2+" /> <exclude name="**/EjbJar.java" unless="jdk1.2+" />
<exclude name="**/*DeploymentTool.java" unless="jdk1.2+" /> <exclude name="**/*DeploymentTool.java" unless="jdk1.2+" />
<exclude name="**/junit/*" unless="junit.present" /> <exclude name="**/junit/*" unless="junit.present" />
<exclude name="**/FTP*.java" unless="ftp.present" />
</javac> </javac>
<copydir src="${src.dir}" dest="${build.classes}"> <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>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>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>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> <li>Dave Walend (<a href="mailto:dwalend@cs.tufts.edu">dwalend@cs.tufts.edu</a>)</li>
</ul> </ul>


@@ -3303,6 +3304,7 @@ and <code>todo.html</code> are excluded.</p>
<h2><a name="optionaltasks">Optional tasks</a></h2> <h2><a name="optionaltasks">Optional tasks</a></h2>
<ul> <ul>
<li><a href="#cab">Cab</a></li> <li><a href="#cab">Cab</a></li>
<li><a href="#ftp">FTP</a></li>
<li><a href="#netrexxc">NetRexxC</a></li> <li><a href="#netrexxc">NetRexxC</a></li>
<li><a href="#renameexts">RenameExtensions</a></li> <li><a href="#renameexts">RenameExtensions</a></li>
<li><a href="#script">Script</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 excluded. Output from the cabarc tool is displayed in the build
output.</p> output.</p>
<hr> <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> <h2><a name="netrexxc">NetRexxC</a></h2>
<h3><b>Description:</b></h3> <h3><b>Description:</b></h3>
<p>Compiles a <a href="http://www2.hursley.ibm.com/netrexx">NetRexx</a> <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 mparse=org.apache.tools.ant.taskdefs.optional.metamata.MParse
junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask
cab=org.apache.tools.ant.taskdefs.optional.Cab cab=org.apache.tools.ant.taskdefs.optional.Cab
ftp=org.apache.tools.ant.taskdefs.optional.FTP


# deprecated ant tasks (kept for back compatibility) # deprecated ant tasks (kept for back compatibility)
javadoc2=org.apache.tools.ant.taskdefs.Javadoc 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