1   /*
2                            AntMake
3   
4       Copyright (C) 2004  Jose San Leandro Armend?riz
5                           jsanleandro@yahoo.es
6                           chousz@yahoo.com
7   
8       This library is free software; you can redistribute it and/or
9       modify it under the terms of the GNU General Public
10      License as published by the Free Software Foundation; either
11      version 2 of the License, or (at your option) any later version.
12  
13      This library is distributed in the hope that it will be useful,
14      but WITHOUT ANY WARRANTY; without even the implied warranty of
15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16      General Public License for more details.
17  
18      You should have received a copy of the GNU General Public
19      License along with this library; if not, write to the Free Software
20      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  
22      Thanks to ACM S.L. for distributing this library under the GPL license.
23      Contact info: jsr000@terra.es
24      Postal Address: c/Playa de Lagoa, 1
25                      Urb. Valdecaba?as
26                      Boadilla del monte
27                      28660 Madrid
28                      Spain
29  
30   ******************************************************************************
31                 This class is based on ChangeLogParser
32                 included in Ant distribution, and whose license details
33                 are the following.
34  
35   *
36   * The Apache Software License, Version 1.1
37   *
38   * Copyright (c) 2002 The Apache Software Foundation.  All rights
39   * reserved.
40   *
41   * Redistribution and use in source and binary forms, with or without
42   * modification, are permitted provided that the following conditions
43   * are met:
44   *
45   * 1. Redistributions of source code must retain the above copyright
46   *    notice, this list of conditions and the following disclaimer.
47   *
48   * 2. Redistributions in binary form must reproduce the above copyright
49   *    notice, this list of conditions and the following disclaimer in
50   *    the documentation and/or other materials provided with the
51   *    distribution.
52   *
53   * 3. The end-user documentation included with the redistribution, if
54   *    any, must include the following acknowlegement:
55   *       "This product includes software developed by the
56   *        Apache Software Foundation (http://www.apache.org/)."
57   *    Alternately, this acknowlegement may appear in the software itself,
58   *    if and wherever such third-party acknowlegements normally appear.
59   *
60   * 4. The names "Ant" and "Apache Software
61   *    Foundation" must not be used to endorse or promote products derived
62   *    from this software without prior written permission. For written
63   *    permission, please contact apache@apache.org.
64   *
65   * 5. Products derived from this software may not be called "Apache"
66   *    nor may "Apache" appear in their names without prior written
67   *    permission of the Apache Group.
68   *
69   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
70   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
71   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
72   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
73   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
74   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
75   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
76   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
77   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
78   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
79   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80   * SUCH DAMAGE.
81   * ====================================================================
82   *
83   * This software consists of voluntary contributions made by many
84   * individuals on behalf of the Apache Software Foundation.  For more
85   * information on the Apache Software Foundation, please see
86   * <http://www.apache.org/>.
87   *
88  
89   ******************************************************************************
90   *
91   * Filename: $RCSfile: ChangeLogParser.java,v $
92   *
93   * Author: Jose San Leandro Armend?riz
94   *
95   * Description: Knows how to parse "cvs log" command output.
96   *
97   * Last modified by: $Author: chous $ at $Date: 2004/01/29 06:44:21 $
98   *
99   * File version: $Revision: 1.3 $
100  *
101  * Project version: $Name:  $
102  *
103  * $Id: ChangeLogParser.java,v 1.3 2004/01/29 06:44:21 chous Exp $
104  *
105  */
106 package org.acmsl.antmake.cvslib;
107 
108 /*
109  * Importing project classes.
110  */
111 import org.acmsl.antmake.cvslib.RcsFile;
112 
113 /*
114  * Importing JDK classes.
115  */
116 import java.text.DateFormat;
117 import java.text.ParseException;
118 import java.text.SimpleDateFormat;
119 import java.util.ArrayList;
120 import java.util.Collection;
121 import java.util.Date;
122 import java.util.HashMap;
123 import java.util.Iterator;
124 import java.util.Map;
125 import java.util.TimeZone;
126 
127 /*
128  * Importing Commons Logging classes.
129  */
130 import org.apache.commons.logging.LogFactory;
131 
132 /***
133  * Knows how to parse "cvs log" command output.
134  * @author <a href="mailto:jsanleandro@yahoo.es"
135            >Jose San Leandro</a>, based on
136  * <a href="mailto:peter@apache.org">Peter Donald</a>'s
137  * ChangeLogParser. It's package-protected, so it had to be basically copied
138  * and pasted.
139  * @version $Revision: 1.3 $
140  * @see org.apache.tools.ant.taskdefs.cvslib.ChangeLogParser
141  */
142 public class ChangeLogParser
143 {
144     /***
145      * A cached empty CvsEntry array.
146      */
147     protected static final CvsEntry[] EMPTY_CVSENTRY_ARRAY = new CvsEntry[0];
148 
149     //private static final int GET_ENTRY = 0;
150     private static final int GET_FILE = 1;
151     private static final int GET_DATE = 2;
152     private static final int GET_COMMENT = 3;
153     private static final int GET_REVISION = 4;
154     private static final int GET_PREVIOUS_REV = 5;
155 
156     /***
157      * The date format returned by cvs log.
158      */
159     public static final DateFormat CVS_LOG_DATE_FORMAT =
160         new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
161 
162     static
163     {
164         TimeZone t_TimeZone = TimeZone.getTimeZone("UTC");
165         CVS_LOG_DATE_FORMAT.setTimeZone(t_TimeZone);
166     }
167 
168     /***
169      * The file name.
170      */
171     private String m__strName;
172 
173     /***
174      * The date.
175      */
176     private String m__strDate;
177 
178     /***
179      * The author.
180      */
181     private String m__strAuthor;
182 
183     /***
184      * The comment.
185      */
186     private String m__strComment;
187 
188     /***
189      * The revision.
190      */
191     private String m__strRevision;
192 
193     /***
194      * The previous revision.
195      */
196     private String m__strPreviousRevision;
197 
198     /***
199      * The variable indicating the current state.
200      */
201     private int m__iCurrentState;
202 
203     /***
204      * The RCS files.
205      */
206     private Map m__mEntries;
207 
208     /***
209      * Creates a ChangeLogParser.
210      */
211     public ChangeLogParser()
212     {
213         inmutableSetCurrentState(GET_FILE);
214     }
215 
216     /***
217      * Specifies the name.
218      * @param name the name of the current CVS file being processed.
219      */
220     protected void setName(String name)
221     {
222         m__strName = name;
223     }
224 
225     /***
226      * Retrieves the name of the current CVS file being processed.
227      * @return such information.
228      */
229     protected String getName()
230     {
231         return m__strName;
232     }
233 
234     /***
235      * Specifies the date.
236      * @param date the date of the current CVS file being processed.
237      */
238     protected void setDate(String date)
239     {
240         m__strDate = date;
241     }
242 
243     /***
244      * Retrieves the date of the current CVS file being processed.
245      * @return such information.
246      */
247     protected String getDate()
248     {
249         return m__strDate;
250     }
251 
252     /***
253      * Specifies the author.
254      * @param author the author of the current CVS file being processed.
255      */
256     protected void setAuthor(String author)
257     {
258         m__strAuthor = author;
259     }
260 
261     /***
262      * Retrieves the author of the current CVS file being processed.
263      * @return such information.
264      */
265     protected String getAuthor()
266     {
267         return m__strAuthor;
268     }
269 
270     /***
271      * Specifies the comment.
272      * @param comment the comment of the CVS file being processed.
273      */
274     protected void setComment(String comment)
275     {
276         m__strComment = comment;
277     }
278 
279     /***
280      * Retrieves the comment of the CVS file being processed.
281      * @return such information.
282      */
283     protected String getComment()
284     {
285         return m__strComment;
286     }
287 
288     /***
289      * Specifies the revision.
290      * @param revision the revision of the current CVS file being processed.
291      */
292     protected void setRevision(String revision)
293     {
294         m__strRevision = revision;
295     }
296 
297     /***
298      * Retrieves the revision of the current CVS file being processed.
299      * @return such information.
300      */
301     protected String getRevision()
302     {
303         return m__strRevision;
304     }
305 
306     /***
307      * Specifies the previous revision.
308      * @param previousRevision the previous revision of the current CVS file
309      * being processed.
310      */
311     protected void setPreviousRevision(String previousRevision)
312     {
313         m__strPreviousRevision = previousRevision;
314     }
315 
316     /***
317      * Retrieves the previous revision of the current CVS file being processed.
318      * @return such information.
319      */
320     protected String getPreviousRevision()
321     {
322         return m__strPreviousRevision;
323     }
324 
325     /***
326      * Specifies the current state of the parser.
327      * @param state the current state of the parser.
328      */
329     private void inmutableSetCurrentState(int state)
330     {
331         m__iCurrentState = state;
332     }
333 
334     /***
335      * Specifies the current state of the parser.
336      * @param state the current state of the parser.
337      */
338     protected void setCurrentState(int state)
339     {
340         inmutableSetCurrentState(state);
341     }
342 
343     /***
344      * Retrieves the current state of the parser.
345      * @return such information.
346      */
347     protected int getCurrentState()
348     {
349         return m__iCurrentState;
350     }
351 
352     /***
353      * Specifies the CVS entries map.
354      * @param map the map.
355      */
356     protected void setEntries(Map map)
357     {
358         m__mEntries = map;
359     }
360 
361     /***
362      * Retrieves the CVS entries map.
363      * @return such map.
364      */
365     protected Map getEntries()
366     {
367         return m__mEntries;
368     }
369 
370     /***
371      * Retrieves the list of RCS entries as an array.
372      * @return such items.
373      */
374     public CvsEntry[] getEntrySetAsArray()
375     {
376         CvsEntry[] result = EMPTY_CVSENTRY_ARRAY;
377 
378         Map t_mEntries = getEntries();
379 
380         if  (t_mEntries != null)
381         {
382             result = new CvsEntry[t_mEntries.size()];
383 
384             Collection t_cEntries = t_mEntries.values();
385 
386             if  (t_cEntries != null)
387             {
388                 Iterator t_EntryIterator = t_cEntries.iterator();
389 
390                 int t_iEntryIndex = 0;
391 
392                 while (   (t_EntryIterator != null)
393                        && (t_EntryIterator.hasNext()))
394                 {
395                     result[t_iEntryIndex++] =
396                         (CvsEntry) t_EntryIterator.next();
397                 }
398             }
399         }
400 
401         return result;
402     }
403 
404     /***
405      * Receives notification about the process writing
406      * to standard output.
407      * @param line the last line read.
408      */
409     public void stdout(String line)
410     {
411         switch(getCurrentState())
412         {
413             case GET_FILE:
414                 // make sure attributes are reset when
415                 // working on a 'new' file.
416                 reset();
417                 processFile(line);
418                 break;
419 
420             case GET_REVISION:
421                 processRevision(line);
422                 break;
423 
424             case GET_DATE:
425                 processDate(line);
426                 break;
427 
428             case GET_COMMENT:
429                 processComment(line);
430                 break;
431 
432             case GET_PREVIOUS_REV:
433                 processGetPreviousRevision(line);
434                 break;
435         }
436     }
437 
438     /***
439      * Processes a line while in <i>GET_COMMENT</i> state.
440      * @param line the line to process.
441      */
442     protected void processComment(String line)
443     {
444         if  (line != null)
445         {
446             String t_strComment = getComment();
447 
448             String t_strLineSeparator =
449                 System.getProperty("line.separator");
450 
451             int t_iEnd;
452 
453             if  (line.startsWith("======"))
454             {
455                 setComment(
456                     removeTrailing(
457                         t_strComment,
458                         t_strLineSeparator.length()));
459 
460                 //We have ended changelog for that particular file
461                 //so we can save it
462                 saveEntry();
463 
464                 setCurrentState(GET_FILE);
465 
466             }
467             else if  (line.startsWith("----------------------------"))
468             {
469                 setComment(
470                     removeTrailing(
471                         t_strComment,
472                         t_strLineSeparator.length()));
473 
474                 setCurrentState(GET_PREVIOUS_REV);
475             }
476             else 
477             {
478                 setComment(line + t_strLineSeparator);
479             }
480         }
481     }
482 
483     /***
484      * Removes trailing substring.
485      * @param input the text to process.
486      * @param suffix the length of the substring to remove at the end.
487      * @return the updated input.
488      */
489     protected String removeTrailing(String input, int suffix)
490     {
491         String result = input;
492 
493         if  (input != null)
494         {
495             int t_iAmountToRemove =
496                 Math.min(input.length(), suffix);
497 
498             result = input.substring(0, input.length() - t_iAmountToRemove);
499         }
500 
501         return result;
502     }
503 
504     /***
505      * Processes a line while in <i>GET_FILE</i> state.
506      * @param line the line to process.
507      */
508     protected void processFile(String line)
509     {
510         if  (line != null)
511         {
512             if  (line.startsWith("Working file:"))
513             {
514                 setName(line.substring(14, line.length()));
515 
516                 setCurrentState(GET_REVISION);
517             }
518         }
519     }
520 
521     /***
522      * Processes a line while in <i>REVISION</i> state.
523      * @param line the line to process.
524      */
525     protected void processRevision(String line)
526     {
527         if  (line != null)
528         {
529             if  (line.startsWith("revision"))
530             {
531                 setRevision(line.substring(9));
532 
533                 setCurrentState(GET_DATE);
534             }
535             else if  (line.startsWith("======"))
536             {
537                 //There was no revisions in this changelog
538                 //entry so lets move unto next file
539                 setCurrentState(GET_FILE);
540             }
541         }
542     }
543 
544     /***
545      * Processes a line while in <i>DATE</i> state.
546      * @param line the line to process.
547      */
548     protected void processDate(String line)
549     {
550         if  (line != null)
551         {
552             if  (line.startsWith("date:"))
553             {
554                 setDate(line.substring(6, 25));
555 
556                 String t_strLineData =
557                     line.substring(line.indexOf(";") + 1);
558 
559                 setAuthor(
560                     t_strLineData.substring(10, t_strLineData.indexOf(";")));
561 
562                 setCurrentState(GET_COMMENT);
563 
564                 //Reset comment to empty here as we can accumulate multiple lines
565                 //in the processComment method
566                 setComment("");
567             }
568         }
569     }
570 
571     /***
572      * Processes a line while in <i>GET_PREVIOUS_REVISION</i> state.
573      * @param line the line to process.
574      */
575     protected void processGetPreviousRevision(String line)
576     {
577         if  (line != null)
578         {
579             if  (!line.startsWith("revision"))
580             {
581                 throw new IllegalStateException(
582                     "Unexpected line from CVS: " + line);
583             }
584             else 
585             {
586                 String t_strPreviousRevision = line.substring(9);
587 
588                 setPreviousRevision(t_strPreviousRevision);
589 
590                 saveEntry();
591 
592                 setRevision(t_strPreviousRevision);
593 
594                 setCurrentState(GET_DATE);
595             }
596         }
597     }
598 
599     /***
600      * Saves the current entry.
601      */
602     protected void saveEntry()
603     {
604         CvsEntry t_Entry;
605 
606         String t_strDate    = getDate();
607         String t_strAuthor  = getAuthor();
608         String t_strComment = getComment();
609 
610         Object t_EntryKey = buildEntryKey(t_strDate, t_strAuthor, t_strComment);
611 
612         Map t_mEntries = getEntries();
613 
614         if  (t_mEntries == null)
615         {
616             t_mEntries = new HashMap();
617             setEntries(t_mEntries);
618         }
619 
620         if  (t_mEntries.containsKey(t_EntryKey))
621         {
622             t_Entry = (CvsEntry) t_mEntries.get(t_EntryKey);
623         }
624         else 
625         {
626             t_Entry =
627                 new CvsEntry(
628                     parseDate(t_strDate), t_strAuthor, t_strComment);
629 
630             t_mEntries.put(t_EntryKey, t_Entry);
631         }
632 
633         t_Entry.add(getName(), getRevision(), getPreviousRevision());
634     }
635 
636     /***
637      * Parses date out from expected format.
638      * @param date the string holding the date.
639      * @return the date object or <code>null</code> if unknown date format.
640      */
641     protected Date parseDate(String date)
642     {
643         Date result = null;
644 
645         try
646         {
647             result = CVS_LOG_DATE_FORMAT.parse(date);
648         }
649         catch (ParseException parseException)
650         {
651             LogFactory.getLog(ChangeLogParser.class).info(
652                 "Couldn't parse date " + date,
653                 parseException);
654         }
655 
656         return result;
657     }
658 
659     /***
660      * Builds a key for an entry.
661      * @param date the entry's date.
662      * @param author the author.
663      * @param comment the comment.
664      * @return a key for such entry.
665      */
666     protected Object buildEntryKey(String date, String author, String comment)
667     {
668         return date + author + comment;
669     }
670 
671     /***
672      * Resets all internal attributes except current state.
673      */
674     protected void reset()
675     {
676         setName(null);
677         setDate(null);
678         setAuthor(null);
679         setComment(null);
680         setRevision(null);
681         setPreviousRevision(null);
682     }
683 }
684 
This page was automatically generated by Maven