Okay, here is a patch to Get.java which adds an optional timestamp for
controlling HTTP downloads.
When the useTimestamp flag is set, then the local file time is used for
controlling download -and any file downloaded has its time set to that of
the remote destination. [That is, if the download information includes a
file time *and* that time is greater than 1/1/70, which can't be
distinguished from 'no timestamp', and the JVM is >= Java1.2)
I have also added the build.xml file to test it, which is somewhat fiddlier
than usual due to the need to test against a web server. And the three test
files I use have been stuck up on an externally accessible web server to
round everything off. Once (if) the patch is applied to Get.java, I'll
submit some documentation changes to match.
An FTP/HTTP PUT counterpart is likely only when I need to use it myself
enough to justify the effort.
-Steve
----- Original Message -----
From: "Stefan Bodewig" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Friday, July 14, 2000 02:38
Subject: Re: [patch] Get.java (was Re: Time-based dependencies)
> SL> 2. Touching the file after download.
>
> Take a look at Expand or Untar for examples of abusing Touch for this.
>
> Stefan
>
You know, there is indeed a fair amount of touch abuse going on. I believe
the touch functionality should really be moved into the Project class at
some point in time.
<?xml version="1.0"?>
<!-- Test matrix for timestamped GET
task: get file which does not exist locally
flags: useFileTime=true
result: file is fetched; timestamp is set to remote time
task: get file which does exist locally
flags: useFileTime=true
result: file is not fetched as date is the same
task: get same file without timestamp check
flags: useFileTime=false
result: file is always fetched; timestamp is set to current time
task: use verbose flag in one download
flags: verbose=true
result: progress indicators appear
task: fetch nonexistent URL
result: no fetch: build error
task: fetch URL for which rights are invalid
result: no fetch: build error
task: fetch file with date in future using timestamp test
result: fetch takes place; date set to future
task: fetch of file which is always regenerated
result: fetch always takes place, date set to regeneration time
task: fetch of file dated 1/1/1970
result: likely that this gets interpreted as "unknown" time ("0") so the touch does not
apply
test: fetch of unreachable host
result: fetch times out
task: Java1.1 repeat of above tasks
result: timestamps of local files do not take place
Reference files are in http://www.iseran.com/stuff/
Jul 14 16:18 file.txt
Dec 31 2009 newfile.txt
Jan 1 1970 oldfile.txt
-->
<!-- ======================================================================= -->
<!-- -->
<!-- ======================================================================= -->
<project name="test-get" default="main" basedir=".">
<target name="main">
<property name="source" value="http://www.iseran.com/stuff" />
<echo message="Cleaning up"/>
<delete dir="." includes="*.txt" />
<echo message="Test: download nonexistent file using timestamp (expected: download)" />
<get src="${source}/file.txt" dest="file.txt" verbose="on" useTimestamp="on"/>
<echo message="Test: download same file again using timestamp (expected: no download)" />
<get src="${source}/file.txt" dest="file.txt" verbose="on" useTimestamp="on"/>
<echo message="Test: download file of date 1/1/1970" />
<get src="${source}/oldfile.txt" dest="oldfile.txt" verbose="on" useTimestamp="on"/>
<echo message="Test: download file of date in future (behaviour may depend on web server)" />
<get src="${source}/newfile.txt" dest="newfile.txt" verbose="on" useTimestamp="on"/>
<get src="${source}/newfile.txt" dest="newfile.txt" verbose="on" useTimestamp="on"/>
<echo message="Regression Test: download file without timestamp (expected: download)" />
<get src="${source}/file.txt" dest="otherfile.txt" verbose="on" useTimestamp="off"/>
<echo message="Regression Test: download file without timestamp again (expected: download)" />
<get src="${source}/file.txt" dest="otherfile.txt" verbose="on" useTimestamp="off"/>
</target>
</project>
RCS file:
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Get.java,v
retrieving revision 1.4
diff -r1.4 Get.java
59a60,61
> import java.util.*;
>
61c63,66
< * 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.
68c73,74
< private String verbose = "";
---
> private boolean verbose = false;
> private boolean useTimestamp = false; //off by default
74c80
< * @exception BuildException Thrown in unrecovrable error.
---
> * @exception BuildException Thrown in unrecoverable error.
87a94,129
> //set the timestamp to the file date.
> long timestamp=0;
> boolean hasTimestamp=false;
> if(useTimestamp && destF.exists()) {
> timestamp=destF.lastModified();
> if (verbose) {
> Date t=new Date(timestamp);
> log("local file date : "+t.toString());
> }
>
> hasTimestamp=true;
> }
>
> //set up the URL connection
> URLConnection connection=url.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.
>
93c135
< is = url.openStream();
---
> is = connection.getInputStream();
110c152
< if ("true".equals(verbose)) System.out.print(".");
---
> if (verbose) System.out.print(".");
112c154
< if( "true".equals(verbose)) System.out.println();
---
> if(verbose) System.out.println();
114a157,172
>
> //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);
> }
>
>
>
121c179,200
<
---
>
> /** set the timestamp of a named file to a specified time.
> @param filename
> @param time in milliseconds since the start of the era
> @returns 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(String filepath, long timemillis) throws
> BuildException {
> if (project.getJavaVersion() != Project.JAVA_1_1) {
> Touch touch = (Touch) project.createTask("touch");
> touch.setOwningTarget(target);
> touch.setFile(filepath);
> touch.setMillis(timemillis);
> touch.touch();
> return true;
>
> } else {
> return false;
> }
> }
146c225
< verbose = v;
---
> verbose = Project.toBoolean(v);
152c231
< * @param v if "true" then be verbose
---
> * @param v if "true" then don't report download errors up to ant
156a236,254
>
> /**
> * Use timestamps, if set to "<CODE>true</CODE>".
> * 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.
> * <br>
> * 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) {
> useTimestamp = v;
> }
>