mbenson 2005/02/25 15:15:16 Modified: src/main/org/apache/tools/ant/taskdefs Tag: ANT_16_BRANCH Get.java . Tag: ANT_16_BRANCH WHATSNEW src/etc/testcases/taskdefs Tag: ANT_16_BRANCH get.xml src/testcases/org/apache/tools/ant/taskdefs Tag: ANT_16_BRANCH GetTest.java Log: Sync Get to HEAD (hope that's okay Steve); in particular sync usetimestamp fix on Java 1.2 Revision Changes Path No revision No revision 1.38.2.5 +262 -151 ant/src/main/org/apache/tools/ant/taskdefs/Get.java Index: Get.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Get.java,v retrieving revision 1.38.2.4 retrieving revision 1.38.2.5 diff -u -r1.38.2.4 -r1.38.2.5 --- Get.java 9 Mar 2004 17:01:33 -0000 1.38.2.4 +++ Get.java 25 Feb 2005 23:15:15 -0000 1.38.2.5 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2004 The Apache Software Foundation + * Copyright 2000-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,19 +17,21 @@ package org.apache.tools.ant.taskdefs; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.JavaEnvUtils; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.PrintStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.Date; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.Task; -import org.apache.tools.ant.util.FileUtils; -import org.apache.tools.ant.util.JavaEnvUtils; /** * Gets a particular file from a URL source. @@ -37,12 +39,14 @@ * actions on failures. NB: access through a firewall only works if the whole * Java runtime is correctly configured. * - * * @since Ant 1.1 * * @ant.task category="network" */ public class Get extends Task { + + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + private URL source; // required private File dest; // required private boolean verbose = false; @@ -52,12 +56,47 @@ private String pword = null; + /** * Does the work. * * @exception BuildException Thrown in unrecoverable error. */ public void execute() throws BuildException { + + //set up logging + int logLevel = Project.MSG_INFO; + DownloadProgress progress = null; + if (verbose) { + progress = new VerboseProgress(System.out); + } + + //execute the get + try { + doGet(logLevel, progress); + } catch (IOException ioe) { + log("Error getting " + source + " to " + dest); + if (!ignoreErrors) { + throw new BuildException(ioe, getLocation()); + } + } + } + + /** + * make a get request, with the supplied progress and logging info. + * All the other config parameters are set at the task level, + * source, dest, ignoreErrors, etc. + * @param logLevel level to log at, see [EMAIL PROTECTED] Project#log(String, int)} + * @param progress progress callback; null for no-callbacks + * @return true for a successful download, false otherwise. + * The return value is only relevant when [EMAIL PROTECTED] #ignoreErrors} is true, as + * when false all failures raise BuildExceptions. + * @throws IOException for network trouble + * @throws BuildException for argument errors, or other trouble when ignoreErrors + * is false. + */ + public boolean doGet(int logLevel, DownloadProgress progress) + throws IOException { if (source == null) { throw new BuildException("src attribute is required", getLocation()); } @@ -68,172 +107,161 @@ if (dest.exists() && dest.isDirectory()) { throw new BuildException("The specified destination is a directory", - getLocation()); + getLocation()); } if (dest.exists() && !dest.canWrite()) { throw new BuildException("Can't write to " + dest.getAbsolutePath(), - getLocation()); + getLocation()); } + //dont do any progress, unless asked + if (progress == null) { + progress = new NullProgress(); + } + log("Getting: " + source, logLevel); + log("To: " + dest.getAbsolutePath(), logLevel); - try { - - log("Getting: " + source); - - //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()); - } + //set the timestamp to the file date. + long timestamp = 0; - hasTimestamp = true; + boolean hasTimestamp = false; + if (useTimestamp && dest.exists()) { + timestamp = dest.lastModified(); + if (verbose) { + Date t = new Date(timestamp); + log("local file date : " + t.toString(), logLevel); } + 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); - } - // prepare Java 1.1 style credentials - if (uname != null || pword != null) { - String up = uname + ":" + pword; - String encoding; - // check to see if sun's Base64 encoder is available. - try { - Object encoder = - Class.forName("sun.misc.BASE64Encoder").newInstance(); - encoding = (String) - encoder.getClass().getMethod("encode", new Class[] {byte[].class}) - .invoke(encoder, new Object[] {up.getBytes()}); - - } catch (Exception ex) { // sun's base64 encoder isn't available - Base64Converter encoder = new Base64Converter(); - encoding = encoder.encode(up.getBytes()); - } - connection.setRequestProperty ("Authorization", - "Basic " + encoding); - } + //set up the URL connection + URLConnection connection = source.openConnection(); + //modify the headers + //NB: things like user authentication could go in here too. + if (hasTimestamp) { + connection.setIfModifiedSince(timestamp); + } + // prepare Java 1.1 style credentials + if (uname != null || pword != null) { + String up = uname + ":" + pword; + String encoding; + //we do not use the sun impl for portability, + //and always use our own implementation for consistent + //testing + Base64Converter encoder = new Base64Converter(); + encoding = encoder.encode(up.getBytes()); + connection.setRequestProperty ("Authorization", + "Basic " + encoding); + } - //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 + //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 - //didn't - log("Not modified - so not downloaded"); - return; - } - // test for 401 result (HTTP only) - if (httpConnection.getResponseCode() + if (httpConnection.getResponseCode() + == HttpURLConnection.HTTP_NOT_MODIFIED + //workaround: doesn't work on 1.2 + || (hasTimestamp + && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2) + && timestamp > httpConnection.getLastModified())) { + //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 + //didn't + log("Not modified - so not downloaded", logLevel); + return false; + // also, if timestamp is roughly >= now, HTTP_NOT_MODIFIED is _not_ + // returned... We may want to remove the 1.2 qualifier above. + } + // test for 401 result (HTTP only) + if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) { - String message = "HTTP Authorization failure"; - if (ignoreErrors) { - log(message, Project.MSG_WARN); - return; - } else { - throw new BuildException(message); - } + String message = "HTTP Authorization failure"; + if (ignoreErrors) { + log(message, logLevel); + return false; + } else { + throw new BuildException(message); } - } - //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) don't include dates, of - //course. - - InputStream is = null; - for (int i = 0; i < 3; i++) { - try { - is = connection.getInputStream(); - break; - } catch (IOException ex) { - log("Error opening connection " + ex); - } + } + + //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) don't include dates, of + //course. + + InputStream is = null; + for (int i = 0; i < 3; i++) { + //this three attempt trick is to get round quirks in different + //Java implementations. Some of them take a few goes to bind + //property; we ignore the first couple of such failures. + try { + is = connection.getInputStream(); + break; + } catch (IOException ex) { + log("Error opening connection " + ex, logLevel); } - if (is == null) { - log("Can't get " + source + " to " + dest); - if (ignoreErrors) { - return; - } - throw new BuildException("Can't get " + source + " to " + dest, - getLocation()); + } + if (is == null) { + log("Can't get " + source + " to " + dest, logLevel); + if (ignoreErrors) { + return false; } + throw new BuildException("Can't get " + source + " to " + dest, + getLocation()); + } - FileOutputStream fos = new FileOutputStream(dest); - boolean finished = false; - try { - byte[] buffer = new byte[100 * 1024]; - int length; - int dots = 0; - - while ((length = is.read(buffer)) >= 0) { - fos.write(buffer, 0, length); - if (verbose) { - System.out.print("."); - if (dots++ > 50) { - System.out.flush(); - dots = 0; - } - } - } - if (verbose) { - System.out.println(); - } - finished = true; - } finally { - if (fos != null) { - fos.close(); - } - is.close(); - // we have started to (over)write dest, but failed. - // Try to delete the garbage we'd otherwise leave - // behind. - if (!finished) { - dest.delete(); - } + FileOutputStream fos = new FileOutputStream(dest); + progress.beginDownload(); + boolean finished = false; + try { + byte[] buffer = new byte[100 * 1024]; + int length; + while ((length = is.read(buffer)) >= 0) { + fos.write(buffer, 0, length); + progress.onTick(); + } + finished = true; + } finally { + FileUtils.close(fos); + FileUtils.close(is); + + // we have started to (over)write dest, but failed. + // Try to delete the garbage we'd otherwise leave + // behind. + if (!finished) { + dest.delete(); } + } + progress.endDownload(); - //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() + //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) { - FileUtils.newFileUtils() - .setFileLastModified(dest, remoteTimestamp); - } + ? " - using current time instead" + : ""), logLevel); } - } catch (IOException ioe) { - log("Error getting " + source + " to " + dest); - if (ignoreErrors) { - return; + if (remoteTimestamp != 0) { + FILE_UTILS.setFileLastModified(dest, remoteTimestamp); } - throw new BuildException(ioe, getLocation()); } + + //successful download + return true; } + /** * Set the URL to get. * @@ -289,9 +317,7 @@ * @param v "true" to enable file time fetching */ public void setUseTimestamp(boolean v) { - if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) { - useTimestamp = v; - } + useTimestamp = v; } @@ -320,7 +346,7 @@ * *********************************************************************/ - private static class Base64Converter { + protected static class Base64Converter { public final char [ ] alphabet = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7 @@ -391,4 +417,89 @@ return new String(out); } } + + public interface DownloadProgress { + /** + * begin a download + */ + public void beginDownload(); + + /** + * tick handler + * + */ + public void onTick(); + + /** + * end a download + */ + public void endDownload(); + } + + /** + * do nothing with progress info + */ + public static class NullProgress implements DownloadProgress { + + /** + * begin a download + */ + public void beginDownload() { + + } + + /** + * tick handler + * + */ + public void onTick() { + } + + /** + * end a download + */ + public void endDownload() { + + } + } + + /** + * verbose progress system prints to some output stream + */ + public static class VerboseProgress implements DownloadProgress { + private int dots = 0; + PrintStream out; + + public VerboseProgress(PrintStream out) { + this.out = out; + } + + /** + * begin a download + */ + public void beginDownload() { + dots = 0; + } + + /** + * tick handler + * + */ + public void onTick() { + out.print("."); + if (dots++ > 50) { + out.flush(); + dots = 0; + } + } + + /** + * end a download + */ + public void endDownload() { + out.println(); + out.flush(); + } + } + } No revision No revision 1.503.2.184 +2 -0 ant/WHATSNEW Index: WHATSNEW =================================================================== RCS file: /home/cvs/ant/WHATSNEW,v retrieving revision 1.503.2.183 retrieving revision 1.503.2.184 diff -u -r1.503.2.183 -r1.503.2.184 --- WHATSNEW 24 Feb 2005 20:25:57 -0000 1.503.2.183 +++ WHATSNEW 25 Feb 2005 23:15:15 -0000 1.503.2.184 @@ -219,6 +219,8 @@ * <javac debug="false"> created an invalid command line when running the Symantec Java compiler. +* Get with usetimestamp did not work on Java 1.2. + Changes from Ant 1.6.1 to Ant 1.6.2 =================================== No revision No revision 1.4.6.1 +44 -0 ant/src/etc/testcases/taskdefs/get.xml Index: get.xml =================================================================== RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/get.xml,v retrieving revision 1.4 retrieving revision 1.4.6.1 diff -u -r1.4 -r1.4.6.1 --- get.xml 8 May 2001 09:35:27 -0000 1.4 +++ get.xml 25 Feb 2005 23:15:16 -0000 1.4.6.1 @@ -24,6 +24,50 @@ <target name="test6"> <get src="http://www.apache.org/" dest="get.tmp"/> + + <fileset id="t6" file="get.tmp" /> + <pathconvert property="t6" refid="t6" setonempty="false" /> + + <fail message="get failed"> + <condition> + <not> + <isset property="t6" /> + </not> + </condition> + </fail> + </target> + + <target name="testUseTimestamp"> + <property name="pat" value="yyyyMMddHHmm" /> + + <tstamp> + <format property="dt" pattern="${pat}" offset="-90" unit="second" /> + </tstamp> + + <touch file="get.tmp" datetime="${dt}" pattern="${pat}" /> + + <get src="http://www.apache.org/" dest="get.tmp" + usetimestamp="true" verbose="true" /> + + <fileset id="ts" file="get.tmp"> + <date when="equal" datetime="${dt}" pattern="${pat}" /> + </fileset> + + <pathconvert property="ts" refid="ts" setonempty="false" /> + + <fail message="get w/ timestamp should have failed."> + <condition> + <not> + <isset property="ts" /> + </not> + </condition> + </fail> + </target> + + <target name="cleanup"> + <delete> + <fileset dir="${basedir}" includes="get.tmp" /> + </delete> </target> </project> No revision No revision 1.7.2.5 +8 -7 ant/src/testcases/org/apache/tools/ant/taskdefs/GetTest.java Index: GetTest.java =================================================================== RCS file: /home/cvs/ant/src/testcases/org/apache/tools/ant/taskdefs/GetTest.java,v retrieving revision 1.7.2.4 retrieving revision 1.7.2.5 diff -u -r1.7.2.4 -r1.7.2.5 --- GetTest.java 9 Mar 2004 17:02:01 -0000 1.7.2.4 +++ GetTest.java 25 Feb 2005 23:15:16 -0000 1.7.2.5 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2001,2004 The Apache Software Foundation + * Copyright 2000-2001, 2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,10 @@ configureProject("src/etc/testcases/taskdefs/get.xml"); } + public void tearDown() { + executeTarget("cleanup"); + } + public void test1() { expectBuildException("test1", "required argument missing"); } @@ -54,13 +58,10 @@ public void test6() { executeTarget("test6"); - java.io.File f = new File(getProjectDir(), "get.tmp"); - if (!f.exists()) { - fail("get failed"); - } else { - f.delete(); - } + } + public void testUseTimestamp() { + executeTarget("testUseTimestamp"); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]