diff options
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.java | 321 |
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; + } +} |