Browse Source

Allow faking of zip entry modification times.

Adds DateUtils.parseLenientDateTime.
master
George Bateman Stefan Bodewig 7 years ago
parent
commit
9d4b432840
2 changed files with 91 additions and 2 deletions
  1. +41
    -2
      src/main/org/apache/tools/ant/taskdefs/Zip.java
  2. +50
    -0
      src/main/org/apache/tools/ant/util/DateUtils.java

+ 41
- 2
src/main/org/apache/tools/ant/taskdefs/Zip.java View File

@@ -25,6 +25,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -55,6 +56,7 @@ import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.ant.types.resources.Union;
import org.apache.tools.ant.types.resources.ZipResource;
import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
import org.apache.tools.ant.util.DateUtils;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.GlobPatternMapper;
@@ -122,6 +124,9 @@ public class Zip extends MatchingTask {
}
};

private String fixedModTime = null; // User-provided.
protected long modTimeMillis = 0; // Calculated.

/**
* If this flag is true, execute() will run most operations twice,
* the first time with {@link #skipWriting skipWriting} set to
@@ -584,6 +589,27 @@ public class Zip extends MatchingTask {
return zip64Mode;
}

/**
* Set all stored file modification times to {@code time}.
* @param time Milliseconds since 1970-01-01 00:00, or
* <code>YYYY-MM-DD{T/ }HH:MM[:SS[.SSS]][ ][±ZZ[[:]ZZ]]</code>, or
* <code>MM/DD/YYYY HH:MM[:SS] {AM/PM}</code>, where {a/b} indicates
* that you must choose one of a or b, and [c] indicates that you
* may use or omit c. ±ZZZZ is the timezone offset, and may be
* literally "Z" to mean GMT.
*/
public void setModificationtime(String time) {
fixedModTime = time;
}

/**
* The file modification time previously provided to
* {@link #setModificationtime(String)} or {@code null} if unset.
*/
public String getModificationtime() {
return fixedModTime;
}

/**
* validate and build
* @throws BuildException on error
@@ -836,6 +862,17 @@ public class Zip extends MatchingTask {
+ archiveType + " file to create!");
}

if (fixedModTime != null) {
try {
modTimeMillis = DateUtils.parseLenientDateTime(fixedModTime).getTime();
} catch (ParseException pe) {
throw new BuildException("Failed to parse date string " + fixedModTime + ".");
}
if (roundUp) {
modTimeMillis += ROUNDUP_MILLIS;
}
}

if (zipFile.exists() && !zipFile.isFile()) {
throw new BuildException(zipFile + " is not a file.");
}
@@ -1716,7 +1753,9 @@ public class Zip extends MatchingTask {
// ZIPs store time with a granularity of 2 seconds, round up
final int millisToAdd = roundUp ? ROUNDUP_MILLIS : 0;

if (dir != null && dir.isExists()) {
if (fixedModTime != null) {
ze.setTime(modTimeMillis);
} else if (dir != null && dir.isExists()) {
ze.setTime(dir.getLastModified() + millisToAdd);
} else {
ze.setTime(System.currentTimeMillis() + millisToAdd);
@@ -1803,7 +1842,7 @@ public class Zip extends MatchingTask {

if (!skipWriting) {
final ZipEntry ze = new ZipEntry(vPath);
ze.setTime(lastModified);
ze.setTime(fixedModTime != null ? modTimeMillis : lastModified);
ze.setMethod(doCompress ? ZipEntry.DEFLATED : ZipEntry.STORED);

/*


+ 50
- 0
src/main/org/apache/tools/ant/util/DateUtils.java View File

@@ -26,6 +26,10 @@ import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.tools.ant.taskdefs.Touch;

/**
* Helper methods to deal with date/time formatting with a specific
@@ -298,4 +302,50 @@ public final class DateUtils {
return parseIso8601Date(datestr);
}
}

final private static ThreadLocal<DateFormat> iso8601WithTimeZone =
new ThreadLocal<DateFormat>() {
@Override protected DateFormat initialValue() {
// An arbitrary easy-to-read format to normalize to.
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z");
}
};
final private static Pattern iso8601normalizer = Pattern.compile(
"^(\\d{4,}-\\d{2}-\\d{2})[Tt ]" + // yyyy-MM-dd
"(\\d{2}:\\d{2}(:\\d{2}(\\.\\d{3})?)?) ?" + // HH:mm:ss.SSS
"(?:Z|([+-]\\d{2})(?::?(\\d{2}))?)?$"); // Z

/**
* Parse a lenient ISO 8601, ms since epoch, or {@code <touch>}-style date.
* That is:
* <ul>
* <li>Milliseconds since 1970-01-01 00:00</li>
* <li><code>YYYY-MM-DD{T| }HH:MM[:SS[.SSS]][ ][±ZZ[[:]ZZ]]</code></li>
* <li><code>MM/DD/YYYY HH:MM[:SS] {AM|PM}</code></li></ul>
* where {a|b} indicates that you must choose one of a or b, and [c]
* indicates that you may use or omit c. ±ZZZZ is the timezone offset, and
* may be literally "Z" to mean GMT.
*/
public static Date parseLenientDateTime(String dateStr) throws ParseException {
try {
return new Date(Long.parseLong(dateStr));
} catch (NumberFormatException nfe) {}

try {
return Touch.DEFAULT_DF_FACTORY.getPrimaryFormat().parse(dateStr);
} catch (ParseException pe) {}

try {
return Touch.DEFAULT_DF_FACTORY.getFallbackFormat().parse(dateStr);
} catch (ParseException pe) {}

Matcher m = iso8601normalizer.matcher(dateStr);
if (!m.find()) throw new ParseException(dateStr, 0);
String normISO = m.group(1) + " "
+ (m.group(3) == null ? m.group(2) + ":00" : m.group(2))
+ (m.group(4) == null ? ".000 " : " ")
+ (m.group(5) == null ? "+00" : m.group(5))
+ (m.group(6) == null ? "00" : m.group(6));
return iso8601WithTimeZone.get().parse(normISO);
}
}

Loading…
Cancel
Save