aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java321
1 files changed, 321 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java
new file mode 100644
index 00000000..0096aadf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+
+import org.apache.tools.ant.taskdefs.AbstractCvsTask;
+import org.apache.tools.ant.util.CollectionUtils;
+
+/**
+ * A class used to parse the output of the CVS log command.
+ *
+ */
+class ChangeLogParser {
+ //private static final int GET_ENTRY = 0;
+ private static final int GET_FILE = 1;
+ private static final int GET_DATE = 2;
+ private static final int GET_COMMENT = 3;
+ 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", 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
+ private String file;
+ private String date;
+ private String author;
+ private String comment;
+ private String revision;
+ private String previousRevision;
+
+ private int status = GET_FILE;
+
+ /** rcs entries */
+ private final Hashtable entries = new Hashtable();
+
+ private final boolean remote;
+ private final String[] moduleNames;
+ private final int[] moduleNameLengths;
+
+ public ChangeLogParser() {
+ this(false, "", CollectionUtils.EMPTY_LIST);
+ }
+
+ public ChangeLogParser(boolean remote, String packageName, List modules) {
+ this.remote = remote;
+
+ ArrayList names = new ArrayList();
+ if (packageName != null) {
+ for (StringTokenizer tok = new StringTokenizer(packageName);
+ tok.hasMoreTokens();) {
+ names.add(tok.nextToken());
+ }
+ }
+ for (Iterator iter = modules.iterator(); iter.hasNext();) {
+ AbstractCvsTask.Module m = (AbstractCvsTask.Module) iter.next();
+ names.add(m.getName());
+ }
+
+ moduleNames = (String[]) names.toArray(new String[names.size()]);
+ moduleNameLengths = new int[moduleNames.length];
+ for (int i = 0; i < moduleNames.length; i++) {
+ moduleNameLengths[i] = moduleNames[i].length();
+ }
+ }
+
+ /**
+ * Get a list of rcs entries as an array.
+ *
+ * @return a list of rcs entries as an array
+ */
+ public CVSEntry[] getEntrySetAsArray() {
+ final CVSEntry[] array = new CVSEntry[ entries.size() ];
+ int i = 0;
+ for (Enumeration e = entries.elements(); e.hasMoreElements();) {
+ array[i++] = (CVSEntry) e.nextElement();
+ }
+ return array;
+ }
+
+ /**
+ * Receive notification about the process writing
+ * to standard output.
+ * @param line the line to process
+ */
+ public void stdout(final String line) {
+ switch(status) {
+ case GET_FILE:
+ // make sure attributes are reset when
+ // working on a 'new' file.
+ reset();
+ processFile(line);
+ break;
+ case GET_REVISION:
+ processRevision(line);
+ break;
+
+ case GET_DATE:
+ processDate(line);
+ break;
+
+ case GET_COMMENT:
+ processComment(line);
+ break;
+
+ case GET_PREVIOUS_REV:
+ processGetPreviousRevision(line);
+ break;
+
+ default:
+ // Do nothing
+ break;
+ }
+ }
+
+ /**
+ * Process a line while in "GET_COMMENT" state.
+ *
+ * @param line the line
+ */
+ private void processComment(final String line) {
+ final String lineSeparator = System.getProperty("line.separator");
+ if (line.equals(
+ "=============================================================================")) {
+ //We have ended changelog for that particular file
+ //so we can save it
+ final int end
+ = comment.length() - lineSeparator.length(); //was -1
+ comment = comment.substring(0, end);
+ saveEntry();
+ status = GET_FILE;
+ } else if (line.equals("----------------------------")) {
+ final int end
+ = comment.length() - lineSeparator.length(); //was -1
+ comment = comment.substring(0, end);
+ status = GET_PREVIOUS_REV;
+ } else {
+ comment += line + lineSeparator;
+ }
+ }
+
+ /**
+ * Process a line while in "GET_FILE" state.
+ *
+ * @param line the line to process
+ */
+ private void processFile(final String line) {
+ if (!remote && line.startsWith("Working file:")) {
+ // CheckStyle:MagicNumber OFF
+ file = line.substring(14, line.length());
+ // CheckStyle:MagicNumber ON
+ status = GET_REVISION;
+ } else if (remote && line.startsWith("RCS file:")) {
+ // exclude the part of the RCS filename up to and
+ // including the module name (and the path separator)
+ int startOfFileName = 0;
+ for (int i = 0; i < moduleNames.length; i++) {
+ int index = line.indexOf(moduleNames[i]);
+ if (index >= 0) {
+ startOfFileName = index + moduleNameLengths[i] + 1;
+ break;
+ }
+ }
+ int endOfFileName = line.indexOf(",v");
+ if (endOfFileName == -1) {
+ file = line.substring(startOfFileName);
+ } else {
+ file = line.substring(startOfFileName, endOfFileName);
+ }
+ status = GET_REVISION;
+ }
+ }
+
+ /**
+ * Process a line while in "REVISION" state.
+ *
+ * @param line the line to process
+ */
+ private void processRevision(final String line) {
+ if (line.startsWith("revision")) {
+ // CheckStyle:MagicNumber OFF
+ revision = line.substring(9);
+ // CheckStyle:MagicNumber ON
+ status = GET_DATE;
+ } else if (line.startsWith("======")) {
+ //There were no revisions in this changelog
+ //entry so lets move onto next file
+ status = GET_FILE;
+ }
+ }
+
+ /**
+ * Process a line while in "DATE" state.
+ *
+ * @param line the line to process
+ */
+ private void processDate(final String line) {
+ if (line.startsWith("date:")) {
+ // 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;
+
+ //Reset comment to empty here as we can accumulate multiple lines
+ //in the processComment method
+ comment = "";
+ }
+ }
+
+ /**
+ * Process a line while in "GET_PREVIOUS_REVISION" state.
+ *
+ * @param line the line to process
+ */
+ private void processGetPreviousRevision(final String line) {
+ if (!line.startsWith("revision ")) {
+ throw new IllegalStateException("Unexpected line from CVS: "
+ + line);
+ }
+ previousRevision = line.substring("revision ".length());
+
+ saveEntry();
+
+ revision = previousRevision;
+ status = GET_DATE;
+ }
+
+ /**
+ * Utility method that saves the current entry.
+ */
+ private void saveEntry() {
+ final String entryKey = date + author + comment;
+ CVSEntry entry;
+ if (!entries.containsKey(entryKey)) {
+ Date dateObject = parseDate(date);
+ entry = new CVSEntry(dateObject, author, comment);
+ entries.put(entryKey, entry);
+ } else {
+ entry = (CVSEntry) entries.get(entryKey);
+ }
+
+ entry.addFile(file, revision, previousRevision);
+ }
+
+ /**
+ * Parse date out from expected format.
+ *
+ * @param date the string holding date
+ * @return the date object or null if unknown date format
+ */
+ private Date parseDate(final String date) {
+ try {
+ return INPUT_DATE.parse(date);
+ } catch (ParseException e) {
+ try {
+ return CVS1129_INPUT_DATE.parse(date);
+ } catch (ParseException e2) {
+ throw new IllegalStateException("Invalid date format: " + date);
+ }
+ }
+ }
+
+ /**
+ * Reset all internal attributes except status.
+ */
+ public void reset() {
+ this.file = null;
+ this.date = null;
+ this.author = null;
+ this.comment = null;
+ this.revision = null;
+ this.previousRevision = null;
+ }
+}