diff --git a/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java b/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java index 45a9c2be2..332175d5c 100644 --- a/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java +++ b/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java @@ -21,6 +21,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; +import java.util.Locale; import java.util.TimeZone; /** @@ -35,13 +36,21 @@ class ChangeLogParser { private static final int GET_REVISION = 4; private static final int GET_PREVIOUS_REV = 5; +// FIXME formatters are not thread-safe + /** input format for dates read in from cvs log */ private static final SimpleDateFormat INPUT_DATE - = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US); + /** + * New formatter used to parse CVS date/timestamp. + */ + private static final SimpleDateFormat CVS1129_INPUT_DATE = + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US); static { TimeZone utc = TimeZone.getTimeZone("UTC"); INPUT_DATE.setTimeZone(utc); + CVS1129_INPUT_DATE.setTimeZone(utc); } //The following is data used while processing stdout of CVS command @@ -168,9 +177,15 @@ class ChangeLogParser { */ private void processDate(final String line) { if (line.startsWith("date:")) { - date = line.substring(6, 25); - String lineData = line.substring(line.indexOf(";") + 1); - author = lineData.substring(10, lineData.indexOf(";")); + // The date format is using a - format since 1.12.9 so we have: + // 1.12.9-: 'date: YYYY/mm/dd HH:mm:ss; author: name;' + // 1.12.9+: 'date: YYYY-mm-dd HH:mm:ss Z; author: name' + int endOfDateIndex = line.indexOf(';'); + date = line.substring("date: ".length(), endOfDateIndex); + + int startOfAuthorIndex = line.indexOf("author: ", endOfDateIndex + 1); + int endOfAuthorIndex = line.indexOf(';', startOfAuthorIndex + 1); + author = line.substring("author: ".length() + startOfAuthorIndex, endOfAuthorIndex); status = GET_COMMENT; @@ -186,11 +201,11 @@ class ChangeLogParser { * @param line the line to process */ private void processGetPreviousRevision(final String line) { - if (!line.startsWith("revision")) { + if (!line.startsWith("revision ")) { throw new IllegalStateException("Unexpected line from CVS: " + line); } - previousRevision = line.substring(9); + previousRevision = line.substring("revision ".length()); saveEntry(); @@ -205,7 +220,8 @@ class ChangeLogParser { final String entryKey = date + author + comment; CVSEntry entry; if (!entries.containsKey(entryKey)) { - entry = new CVSEntry(parseDate(date), author, comment); + Date dateObject = parseDate(date); + entry = new CVSEntry(dateObject, author, comment); entries.put(entryKey, entry); } else { entry = (CVSEntry) entries.get(entryKey); @@ -224,9 +240,11 @@ class ChangeLogParser { try { return INPUT_DATE.parse(date); } catch (ParseException e) { - //final String message = REZ.getString( "changelog.bat-date.error", date ); - //getContext().error( message ); - return null; + try { + return CVS1129_INPUT_DATE.parse(date); + } catch (ParseException e2) { + throw new IllegalStateException("Invalid date format: " + date); + } } } diff --git a/src/testcases/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParserTest.java b/src/testcases/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParserTest.java new file mode 100644 index 000000000..b4fb1231e --- /dev/null +++ b/src/testcases/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParserTest.java @@ -0,0 +1,46 @@ +package org.apache.tools.ant.taskdefs.cvslib; + +import junit.framework.TestCase; + +import java.util.Calendar; +import java.util.Locale; +import java.util.TimeZone; +import java.util.Date; + +/** + * Minimal test of the parser implementation + */ +public class ChangeLogParserTest extends TestCase { + + protected ChangeLogParser parser = new ChangeLogParser(); + + public void testOldCvsFormat() throws Exception { + parser.stdout("Working file: build.xml"); + parser.stdout("revision 1.475"); + parser.stdout("date: 2004/06/05 16:10:32; author: somebody; state: Exp; lines: +2 -2"); + parser.stdout("I have done something. I swear."); + parser.stdout("============================================================================="); + CVSEntry[] entries = parser.getEntrySetAsArray(); + assertEquals("somebody", entries[0].getAuthor()); + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US); + cal.set(Calendar.MILLISECOND, 0); + cal.set(2004, Calendar.JUNE, 5, 16, 10, 32); + Date date = cal.getTime(); + assertEquals(date, entries[0].getDate()); + } + + public void testCvs112Format() throws Exception { + parser.stdout("Working file: build.xml"); + parser.stdout("revision 1.475"); + parser.stdout("date: 2004-06-05 16:10:32 +0000; author: somebody; state: Exp; lines: +2 -2"); + parser.stdout("I have done something. I swear."); + parser.stdout("============================================================================="); + CVSEntry[] entries = parser.getEntrySetAsArray(); + assertEquals("somebody", entries[0].getAuthor()); + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US); + cal.set(Calendar.MILLISECOND, 0); + cal.set(2004, Calendar.JUNE, 5, 16, 10, 32); + Date date = cal.getTime(); + assertEquals(date, entries[0].getDate()); + } +}