diff --git a/src/main/org/apache/tools/ant/BuildException.java b/src/main/org/apache/tools/ant/BuildException.java
index b0e6c185a..5e8819824 100644
--- a/src/main/org/apache/tools/ant/BuildException.java
+++ b/src/main/org/apache/tools/ant/BuildException.java
@@ -132,6 +132,18 @@ public class BuildException extends RuntimeException {
this.location = location;
}
+ /**
+ * Constructs an exception with the given exception as
+ * a root cause and a location in a file.
+ * @param cause Exception that might have cause this one.
+ * @param location Location in the project file where the error occured.
+ */
+
+ public BuildException(Throwable cause, Location location) {
+ this(cause);
+ this.location = location;
+ }
+
/**
* Returns the nested exception.
*/
diff --git a/src/main/org/apache/tools/ant/taskdefs/Expand.java b/src/main/org/apache/tools/ant/taskdefs/Expand.java
index 4edee4fd5..707f1dec1 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Expand.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Expand.java
@@ -61,7 +61,7 @@ import java.util.zip.*;
* Unzip a file.
*
* @author costin@dnt.ro
- * @author Stefan Bodewig stefan.bodewig@megabit.net
+ * @author Stefan Bodewig
*/
public class Expand extends Task {
private String dest; // req
@@ -81,6 +81,8 @@ public class Expand extends Task {
Touch touch = (Touch) project.createTask("touch");
touch.setOwningTarget(target);
+ touch.setTaskName(getTaskName());
+ touch.setLocation(getLocation());
File srcF=project.resolveFile(source);
File dir=project.resolveFile(dest);
@@ -116,7 +118,7 @@ public class Expand extends Task {
}
if (project.getJavaVersion() != Project.JAVA_1_1) {
- touch.setFile(f.getAbsolutePath());
+ touch.setFile(f);
touch.setMillis(ze.getTime());
touch.touch();
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/Get.java b/src/main/org/apache/tools/ant/taskdefs/Get.java
index 1e32ffcc7..5c3f3b5dc 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Get.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Get.java
@@ -57,40 +57,79 @@ package org.apache.tools.ant.taskdefs;
import org.apache.tools.ant.*;
import java.io.*;
import java.net.*;
+import java.util.*;
+
/**
- * Get a particular source.
+ * Get a particular file from a URL source.
+ * Options include verbose reporting, timestamp based fetches and controlling
+ * actions on failures. NB: access through a firewall only works if the whole
+ * Java runtime is correctly configured.
*
* @author costin@dnt.ro
*/
public class Get extends Task {
- private String source; // required
- private String dest; // required
- private String verbose = "";
- String ignoreErrors=null;
+ private URL source; // required
+ private File dest; // required
+ private boolean verbose = false;
+ private boolean useTimestamp = false; //off by default
+ private boolean ignoreErrors = false;
/**
* Does the work.
*
- * @exception BuildException Thrown in unrecovrable error.
+ * @exception BuildException Thrown in unrecoverable error.
*/
public void execute() throws BuildException {
try {
- URL url = null;
- try {
- url = new URL(source);
- } catch (MalformedURLException e) {
- throw new BuildException(e.toString());
- }
log("Getting: " + source);
- File destF=new File(dest);
- FileOutputStream fos = new FileOutputStream(destF);
+ //set the timestamp to the file date.
+ long timestamp=0;
+
+ boolean hasTimestamp=false;
+ if(useTimestamp && dest.exists()) {
+ timestamp=dest.lastModified();
+ if (verbose) {
+ Date t=new Date(timestamp);
+ log("local file date : "+t.toString());
+ }
+
+ hasTimestamp=true;
+ }
+
+ //set up the URL connection
+ URLConnection connection=source.openConnection();
+ //modify the headers
+ //NB: things like user authentication could go in here too.
+ if(useTimestamp && hasTimestamp) {
+ connection.setIfModifiedSince(timestamp);
+ }
+
+ //connect to the remote site (may take some time)
+ connection.connect();
+ //next test for a 304 result (HTTP only)
+ if(connection instanceof HttpURLConnection) {
+ HttpURLConnection httpConnection=(HttpURLConnection)connection;
+ if(httpConnection.getResponseCode()==HttpURLConnection.HTTP_NOT_MODIFIED) {
+ //not modified so no file download. just return instead
+ //and trace out something so the user doesn't think that the
+ //download happened when it didnt
+ log("Not modified - so not downloaded");
+ return;
+ }
+ }
+
+ //REVISIT: at this point even non HTTP connections may support the if-modified-since
+ //behaviour -we just check the date of the content and skip the write if it is not
+ //newer. Some protocols (FTP) dont include dates, of course.
+
+ FileOutputStream fos = new FileOutputStream(dest);
InputStream is=null;
for( int i=0; i< 3 ; i++ ) {
try {
- is = url.openStream();
+ is = connection.getInputStream();
break;
} catch( IOException ex ) {
log( "Error opening connection " + ex );
@@ -98,8 +137,10 @@ public class Get extends Task {
}
if( is==null ) {
log( "Can't get " + source + " to " + dest);
- if( ignoreErrors != null ) return;
- throw new BuildException( "Can't get " + source + " to " + dest);
+ if(ignoreErrors)
+ return;
+ throw new BuildException( "Can't get " + source + " to " + dest,
+ location);
}
byte[] buffer = new byte[100 * 1024];
@@ -107,25 +148,70 @@ public class Get extends Task {
while ((length = is.read(buffer)) >= 0) {
fos.write(buffer, 0, length);
- if ("true".equals(verbose)) System.out.print(".");
+ if (verbose) System.out.print(".");
}
- if( "true".equals(verbose)) System.out.println();
+ if(verbose) System.out.println();
fos.close();
is.close();
+
+ //if (and only if) the use file time option is set, then the
+ //saved file now has its timestamp set to that of the downloaded file
+ if(useTimestamp) {
+ long remoteTimestamp=connection.getLastModified();
+ if (verbose) {
+ Date t=new Date(remoteTimestamp);
+ log("last modified = "+t.toString()
+ +((remoteTimestamp==0)?" - using current time instead":""));
+ }
+ if(remoteTimestamp!=0)
+ touchFile(dest,remoteTimestamp);
+ }
+
+
+
} catch (IOException ioe) {
log("Error getting " + source + " to " + dest );
- if( ignoreErrors != null ) return;
- throw new BuildException(ioe.toString());
+ if(ignoreErrors)
+ return;
+ throw new BuildException(ioe, location);
}
}
+
+ /**
+ * set the timestamp of a named file to a specified time.
+ *
+ * @param filename
+ * @param time in milliseconds since the start of the era
+ * @return true if it succeeded. False means that this is a
+ * java1.1 system and that file times can not be set
+ *@exception BuildException Thrown in unrecoverable error. Likely
+ *this comes from file access failures.
+ */
+ protected boolean touchFile(File file, long timemillis)
+ throws BuildException {
+
+ if (project.getJavaVersion() != Project.JAVA_1_1) {
+ Touch touch = (Touch) project.createTask("touch");
+ touch.setOwningTarget(target);
+ touch.setTaskName(getTaskName());
+ touch.setLocation(getLocation());
+ touch.setFile(file);
+ touch.setMillis(timemillis);
+ touch.touch();
+ return true;
+
+ } else {
+ return false;
+ }
+ }
/**
* Set the URL.
*
- * @param d URL for the file.
+ * @param u URL for the file.
*/
- public void setSrc(String d) {
- this.source=d;
+ public void setSrc(URL u) {
+ this.source = u;
}
/**
@@ -133,7 +219,7 @@ public class Get extends Task {
*
* @param dest Path to file.
*/
- public void setDest(String dest) {
+ public void setDest(File dest) {
this.dest = dest;
}
@@ -142,16 +228,38 @@ public class Get extends Task {
*
* @param v if "true" then be verbose
*/
- public void setVerbose(String v) {
+ public void setVerbose(boolean v) {
verbose = v;
}
/**
* Don't stop if get fails if set to "true
".
*
- * @param v if "true" then be verbose
+ * @param v if "true" then don't report download errors up to ant
*/
- public void setIgnoreErrors(String v) {
+ public void setIgnoreErrors(boolean v) {
ignoreErrors = v;
}
+
+ /**
+ * Use timestamps, if set to "true
".
+ *
+ *
In this situation, the if-modified-since header is set so that the file is
+ * only fetched if it is newer than the local file (or there is no local file)
+ * This flag is only valid on HTTP connections, it is ignored in other cases.
+ * When the flag is set, the local copy of the downloaded file will also
+ * have its timestamp set to the remote file time.
+ *
+ * Note that remote files of date 1/1/1970 (GMT) are treated as 'no timestamp', and
+ * web servers often serve files with a timestamp in the future by replacing their timestamp
+ * with that of the current time. Also, inter-computer clock differences can cause no end of
+ * grief.
+ * @param v "true" to enable file time fetching
+ */
+ public void setUseTimestamp(boolean v) {
+ if (project.getJavaVersion() != Project.JAVA_1_1) {
+ useTimestamp = v;
+ }
+ }
+
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/Touch.java b/src/main/org/apache/tools/ant/taskdefs/Touch.java
index acd3be1e7..1d158be84 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Touch.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Touch.java
@@ -73,7 +73,7 @@ import java.util.Locale;
* created. Setting the modification time of files is not supported in
* JDK 1.1.
*
- * @author Stefan Bodewig stefan.bodewig@megabit.net
+ * @author Stefan Bodewig
*/
public class Touch extends Task {
@@ -87,8 +87,8 @@ public class Touch extends Task {
/**
* The name of the file to touch.
*/
- public void setFile(String name) {
- file = project.resolveFile(name);
+ public void setFile(File file) {
+ this.file = file;
}
/**
diff --git a/src/main/org/apache/tools/ant/taskdefs/Untar.java b/src/main/org/apache/tools/ant/taskdefs/Untar.java
index 8d3d719c0..162231483 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Untar.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Untar.java
@@ -63,7 +63,7 @@ import java.io.*;
*
* Heavily based on the Expand task.
*
- * @author Stefan Bodewig stefan.bodewig@megabit.net
+ * @author Stefan Bodewig
*/
public class Untar extends Task {
private String dest; // req
@@ -78,6 +78,8 @@ public class Untar extends Task {
Touch touch = (Touch) project.createTask("touch");
touch.setOwningTarget(target);
+ touch.setTaskName(getTaskName());
+ touch.setLocation(getLocation());
File srcF=project.resolveFile(source);
@@ -123,7 +125,7 @@ public class Untar extends Task {
}
if (project.getJavaVersion() != Project.JAVA_1_1) {
- touch.setFile(f.getAbsolutePath());
+ touch.setFile(f);
touch.setMillis(te.getModTime().getTime());
touch.touch();
}