1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.cvslib;
  18. import java.text.ParseException;
  19. import java.text.SimpleDateFormat;
  20. import java.util.Date;
  21. import java.util.Enumeration;
  22. import java.util.Hashtable;
  23. import java.util.TimeZone;
  24. /**
  25. * A class used to parse the output of the CVS log command.
  26. *
  27. * @version $Revision: 1.22.2.4 $ $Date: 2004/03/09 17:01:40 $
  28. */
  29. class ChangeLogParser {
  30. //private static final int GET_ENTRY = 0;
  31. private static final int GET_FILE = 1;
  32. private static final int GET_DATE = 2;
  33. private static final int GET_COMMENT = 3;
  34. private static final int GET_REVISION = 4;
  35. private static final int GET_PREVIOUS_REV = 5;
  36. /** input format for dates read in from cvs log */
  37. private static final SimpleDateFormat c_inputDate
  38. = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
  39. static {
  40. TimeZone utc = TimeZone.getTimeZone("UTC");
  41. c_inputDate.setTimeZone(utc);
  42. }
  43. //The following is data used while processing stdout of CVS command
  44. private String m_file;
  45. private String m_date;
  46. private String m_author;
  47. private String m_comment;
  48. private String m_revision;
  49. private String m_previousRevision;
  50. private int m_status = GET_FILE;
  51. /** rcs entries */
  52. private final Hashtable m_entries = new Hashtable();
  53. /**
  54. * Get a list of rcs entries as an array.
  55. *
  56. * @return a list of rcs entries as an array
  57. */
  58. CVSEntry[] getEntrySetAsArray() {
  59. final CVSEntry[] array = new CVSEntry[ m_entries.size() ];
  60. Enumeration e = m_entries.elements();
  61. int i = 0;
  62. while (e.hasMoreElements()) {
  63. array[i++] = (CVSEntry) e.nextElement();
  64. }
  65. return array;
  66. }
  67. /**
  68. * Receive notification about the process writing
  69. * to standard output.
  70. */
  71. public void stdout(final String line) {
  72. switch(m_status) {
  73. case GET_FILE:
  74. // make sure attributes are reset when
  75. // working on a 'new' file.
  76. reset();
  77. processFile(line);
  78. break;
  79. case GET_REVISION:
  80. processRevision(line);
  81. break;
  82. case GET_DATE:
  83. processDate(line);
  84. break;
  85. case GET_COMMENT:
  86. processComment(line);
  87. break;
  88. case GET_PREVIOUS_REV:
  89. processGetPreviousRevision(line);
  90. break;
  91. }
  92. }
  93. /**
  94. * Process a line while in "GET_COMMENT" state.
  95. *
  96. * @param line the line
  97. */
  98. private void processComment(final String line) {
  99. final String lineSeparator = System.getProperty("line.separator");
  100. if (line.startsWith("======")) {
  101. //We have ended changelog for that particular file
  102. //so we can save it
  103. final int end
  104. = m_comment.length() - lineSeparator.length(); //was -1
  105. m_comment = m_comment.substring(0, end);
  106. saveEntry();
  107. m_status = GET_FILE;
  108. } else if (line.startsWith("----------------------------")) {
  109. final int end
  110. = m_comment.length() - lineSeparator.length(); //was -1
  111. m_comment = m_comment.substring(0, end);
  112. m_status = GET_PREVIOUS_REV;
  113. } else {
  114. m_comment += line + lineSeparator;
  115. }
  116. }
  117. /**
  118. * Process a line while in "GET_FILE" state.
  119. *
  120. * @param line the line
  121. */
  122. private void processFile(final String line) {
  123. if (line.startsWith("Working file:")) {
  124. m_file = line.substring(14, line.length());
  125. m_status = GET_REVISION;
  126. }
  127. }
  128. /**
  129. * Process a line while in "REVISION" state.
  130. *
  131. * @param line the line
  132. */
  133. private void processRevision(final String line) {
  134. if (line.startsWith("revision")) {
  135. m_revision = line.substring(9);
  136. m_status = GET_DATE;
  137. } else if (line.startsWith("======")) {
  138. //There was no revisions in this changelog
  139. //entry so lets move unto next file
  140. m_status = GET_FILE;
  141. }
  142. }
  143. /**
  144. * Process a line while in "DATE" state.
  145. *
  146. * @param line the line
  147. */
  148. private void processDate(final String line) {
  149. if (line.startsWith("date:")) {
  150. m_date = line.substring(6, 25);
  151. String lineData = line.substring(line.indexOf(";") + 1);
  152. m_author = lineData.substring(10, lineData.indexOf(";"));
  153. m_status = GET_COMMENT;
  154. //Reset comment to empty here as we can accumulate multiple lines
  155. //in the processComment method
  156. m_comment = "";
  157. }
  158. }
  159. /**
  160. * Process a line while in "GET_PREVIOUS_REVISION" state.
  161. *
  162. * @param line the line
  163. */
  164. private void processGetPreviousRevision(final String line) {
  165. if (!line.startsWith("revision")) {
  166. throw new IllegalStateException("Unexpected line from CVS: "
  167. + line);
  168. }
  169. m_previousRevision = line.substring(9);
  170. saveEntry();
  171. m_revision = m_previousRevision;
  172. m_status = GET_DATE;
  173. }
  174. /**
  175. * Utility method that saves the current entry.
  176. */
  177. private void saveEntry() {
  178. final String entryKey = m_date + m_author + m_comment;
  179. CVSEntry entry;
  180. if (!m_entries.containsKey(entryKey)) {
  181. entry = new CVSEntry(parseDate(m_date), m_author, m_comment);
  182. m_entries.put(entryKey, entry);
  183. } else {
  184. entry = (CVSEntry) m_entries.get(entryKey);
  185. }
  186. entry.addFile(m_file, m_revision, m_previousRevision);
  187. }
  188. /**
  189. * Parse date out from expected format.
  190. *
  191. * @param date the string holding dat
  192. * @return the date object or null if unknown date format
  193. */
  194. private Date parseDate(final String date) {
  195. try {
  196. return c_inputDate.parse(date);
  197. } catch (ParseException e) {
  198. //final String message = REZ.getString( "changelog.bat-date.error", date );
  199. //getContext().error( message );
  200. return null;
  201. }
  202. }
  203. /**
  204. * reset all internal attributes except status.
  205. */
  206. private void reset() {
  207. m_file = null;
  208. m_date = null;
  209. m_author = null;
  210. m_comment = null;
  211. m_revision = null;
  212. m_previousRevision = null;
  213. }
  214. }