Coverage Report - org.apache.maven.scm.provider.cvslib.command.changelog.CvsChangeLogConsumer
 
Classes in this File Line Coverage Branch Coverage Complexity
CvsChangeLogConsumer
92 %
84/91
69 %
27/39
2,562
CvsChangeLogConsumer$1
100 %
2/2
N/A
2,562
 
 1  
 package org.apache.maven.scm.provider.cvslib.command.changelog;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  * http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.scm.ChangeFile;
 23  
 import org.apache.maven.scm.ChangeSet;
 24  
 import org.apache.maven.scm.log.ScmLogger;
 25  
 import org.apache.maven.scm.util.AbstractConsumer;
 26  
 
 27  
 import java.util.ArrayList;
 28  
 import java.util.Collections;
 29  
 import java.util.Comparator;
 30  
 import java.util.Iterator;
 31  
 import java.util.List;
 32  
 import java.util.StringTokenizer;
 33  
 
 34  
 /**
 35  
  * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse </a>
 36  
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
 37  
  * @author Olivier Lamy
 38  
  * @version $Id: CvsChangeLogConsumer.java 1054408 2011-01-02 14:05:25Z olamy $
 39  
  */
 40  
 public class CvsChangeLogConsumer
 41  
     extends AbstractConsumer
 42  
 {
 43  1
     private List<ChangeSet> entries = new ArrayList<ChangeSet>();
 44  
 
 45  
     // state machine constants for reading cvs output
 46  
 
 47  
     /**
 48  
      * expecting file information
 49  
      */
 50  
     private static final int GET_FILE = 1;
 51  
 
 52  
     /**
 53  
      * expecting date
 54  
      */
 55  
     private static final int GET_DATE = 2;
 56  
 
 57  
     /**
 58  
      * expecting comments
 59  
      */
 60  
     private static final int GET_COMMENT = 3;
 61  
 
 62  
     /**
 63  
      * expecting revision
 64  
      */
 65  
     private static final int GET_REVISION = 4;
 66  
 
 67  
     /**
 68  
      * Marks start of file data
 69  
      */
 70  
     private static final String START_FILE = "Working file: ";
 71  
 
 72  
     /**
 73  
      * Marks end of file
 74  
      */
 75  
     private static final String END_FILE =
 76  
         "===================================" + "==========================================";
 77  
 
 78  
     /**
 79  
      * Marks start of revision
 80  
      */
 81  
     private static final String START_REVISION = "----------------------------";
 82  
 
 83  
     /**
 84  
      * Marks revision data
 85  
      */
 86  
     private static final String REVISION_TAG = "revision ";
 87  
 
 88  
     /**
 89  
      * Marks date data
 90  
      */
 91  
     private static final String DATE_TAG = "date: ";
 92  
 
 93  
     /**
 94  
      * current status of the parser
 95  
      */
 96  1
     private int status = GET_FILE;
 97  
 
 98  
     /**
 99  
      * the current log entry being processed by the parser
 100  
      */
 101  1
     private ChangeSet currentChange = null;
 102  
 
 103  
     /**
 104  
      * the current file being processed by the parser
 105  
      */
 106  1
     private ChangeFile currentFile = null;
 107  
 
 108  
     private String userDatePattern;
 109  
 
 110  
     public CvsChangeLogConsumer( ScmLogger logger, String userDatePattern )
 111  
     {
 112  1
         super( logger );
 113  
 
 114  1
         this.userDatePattern = userDatePattern;
 115  1
     }
 116  
 
 117  
     public List<ChangeSet> getModifications()
 118  
     {
 119  1
         Collections.sort( entries, new Comparator<ChangeSet>()
 120  3
         {
 121  
             public int compare( ChangeSet set1, ChangeSet set2 )
 122  
             {
 123  2
                 return set1.getDate().compareTo( set2.getDate() );
 124  
             }
 125  
         } );
 126  1
         List<ChangeSet> fixedModifications = new ArrayList<ChangeSet>();
 127  1
         ChangeSet currentEntry = null;
 128  1
         for ( Iterator<ChangeSet> entryIterator = entries.iterator(); entryIterator.hasNext(); )
 129  
         {
 130  3
             ChangeSet entry = (ChangeSet) entryIterator.next();
 131  3
             if ( currentEntry == null )
 132  
             {
 133  1
                 currentEntry = entry;
 134  
             }
 135  2
             else if ( areEqual( currentEntry, entry ) )
 136  
             {
 137  0
                 currentEntry.addFile( (ChangeFile) entry.getFiles().get( 0 ) );
 138  
             }
 139  
             else
 140  
             {
 141  2
                 fixedModifications.add( currentEntry );
 142  2
                 currentEntry = entry;
 143  
             }
 144  3
         }
 145  1
         if ( currentEntry != null )
 146  
         {
 147  1
             fixedModifications.add( currentEntry );
 148  
         }
 149  1
         return fixedModifications;
 150  
     }
 151  
 
 152  
     private boolean areEqual( ChangeSet set1, ChangeSet set2 )
 153  
     {
 154  2
         if ( set1.getAuthor().equals( set2.getAuthor() ) && set1.getComment().equals( set2.getComment() )
 155  
             && set1.getDate().equals( set2.getDate() ) )
 156  
         {
 157  0
             return true;
 158  
         }
 159  2
         return false;
 160  
     }
 161  
 
 162  
     /** {@inheritDoc} */
 163  
     public void consumeLine( String line )
 164  
     {
 165  51
         if ( getLogger().isDebugEnabled() )
 166  
         {
 167  0
             getLogger().debug( line );
 168  
         }
 169  
         try
 170  
         {
 171  51
             switch ( getStatus() )
 172  
             {
 173  
                 case GET_FILE:
 174  9
                     processGetFile( line );
 175  9
                     break;
 176  
                 case GET_REVISION:
 177  33
                     processGetRevision( line );
 178  33
                     break;
 179  
                 case GET_DATE:
 180  3
                     processGetDate( line );
 181  3
                     break;
 182  
                 case GET_COMMENT:
 183  6
                     processGetComment( line );
 184  6
                     break;
 185  
                 default:
 186  0
                     throw new IllegalStateException( "Unknown state: " + status );
 187  
             }
 188  
         }
 189  0
         catch ( Throwable ex )
 190  
         {
 191  0
             if ( getLogger().isWarnEnabled() )
 192  
             {
 193  0
                 getLogger().warn( "Exception in the cvs changelog consumer.", ex );
 194  
             }
 195  51
         }
 196  51
     }
 197  
 
 198  
     /**
 199  
      * Add a change log entry to the list (if it's not already there) with the
 200  
      * given file.
 201  
      *
 202  
      * @param entry a {@link ChangeSet}to be added to the list if another
 203  
      *              with the same key doesn't exist already. If the entry's author
 204  
      *              is null, the entry wont be added
 205  
      * @param file  a {@link ChangeFile}to be added to the entry
 206  
      */
 207  
     private void addEntry( ChangeSet entry, ChangeFile file )
 208  
     {
 209  
         // do not add if entry is not populated
 210  4
         if ( entry.getAuthor() == null )
 211  
         {
 212  1
             return;
 213  
         }
 214  
 
 215  3
         entry.addFile( file );
 216  
 
 217  3
         entries.add( entry );
 218  3
     }
 219  
 
 220  
     /**
 221  
      * Process the current input line in the Get File state.
 222  
      *
 223  
      * @param line a line of text from the cvs log output
 224  
      */
 225  
     private void processGetFile( String line )
 226  
     {
 227  9
         if ( line.startsWith( START_FILE ) )
 228  
         {
 229  3
             setCurrentChange( new ChangeSet() );
 230  3
             setCurrentFile( new ChangeFile( line.substring( START_FILE.length(), line.length() ) ) );
 231  3
             setStatus( GET_REVISION );
 232  
         }
 233  9
     }
 234  
 
 235  
     /**
 236  
      * Process the current input line in the Get Revision state.
 237  
      *
 238  
      * @param line a line of text from the cvs log output
 239  
      */
 240  
     private void processGetRevision( String line )
 241  
     {
 242  33
         if ( line.startsWith( REVISION_TAG ) )
 243  
         {
 244  3
             getCurrentFile().setRevision( line.substring( REVISION_TAG.length() ) );
 245  3
             setStatus( GET_DATE );
 246  
         }
 247  30
         else if ( line.startsWith( END_FILE ) )
 248  
         {
 249  
             // If we encounter an end of file line, it means there
 250  
             // are no more revisions for the current file.
 251  
             // there could also be a file still being processed.
 252  1
             setStatus( GET_FILE );
 253  1
             addEntry( getCurrentChange(), getCurrentFile() );
 254  
         }
 255  33
     }
 256  
 
 257  
     /**
 258  
      * Process the current input line in the Get Date state.
 259  
      *
 260  
      * @param line a line of text from the cvs log output
 261  
      */
 262  
     private void processGetDate( String line )
 263  
     {
 264  3
         if ( line.startsWith( DATE_TAG ) )
 265  
         {
 266  3
             StringTokenizer tokenizer = new StringTokenizer( line, ";" );
 267  
             // date: YYYY/mm/dd HH:mm:ss [Z]; author: name;...
 268  
 
 269  3
             String datePart = tokenizer.nextToken().trim();
 270  3
             String dateTime = datePart.substring( "date: ".length() );
 271  3
             StringTokenizer dateTokenizer = new StringTokenizer( dateTime, " " );
 272  3
             if ( dateTokenizer.countTokens() == 2 )
 273  
             {
 274  3
                 dateTime += " UTC";
 275  
             }
 276  3
             getCurrentChange().setDate( dateTime, userDatePattern );
 277  
 
 278  3
             String authorPart = tokenizer.nextToken().trim();
 279  3
             String author = authorPart.substring( "author: ".length() );
 280  3
             getCurrentChange().setAuthor( author );
 281  3
             setStatus( GET_COMMENT );
 282  
         }
 283  3
     }
 284  
 
 285  
     /**
 286  
      * Process the current input line in the Get Comment state.
 287  
      *
 288  
      * @param line a line of text from the cvs log output
 289  
      */
 290  
     private void processGetComment( String line )
 291  
     {
 292  6
         if ( line.startsWith( START_REVISION ) )
 293  
         {
 294  
             // add entry, and set state to get revision
 295  1
             addEntry( getCurrentChange(), getCurrentFile() );
 296  
             // new change log entry
 297  1
             setCurrentChange( new ChangeSet() );
 298  
             // same file name, but different rev
 299  1
             setCurrentFile( new ChangeFile( getCurrentFile().getName() ) );
 300  1
             setStatus( GET_REVISION );
 301  
         }
 302  5
         else if ( line.startsWith( END_FILE ) )
 303  
         {
 304  2
             addEntry( getCurrentChange(), getCurrentFile() );
 305  2
             setStatus( GET_FILE );
 306  
         }
 307  
         else
 308  
         {
 309  
             // keep gathering comments
 310  3
             getCurrentChange().setComment( getCurrentChange().getComment() + line + "\n" );
 311  
         }
 312  6
     }
 313  
 
 314  
     /**
 315  
      * Getter for property currentFile.
 316  
      *
 317  
      * @return Value of property currentFile.
 318  
      */
 319  
     private ChangeFile getCurrentFile()
 320  
     {
 321  8
         return currentFile;
 322  
     }
 323  
 
 324  
     /**
 325  
      * Setter for property currentFile.
 326  
      *
 327  
      * @param currentFile New value of property currentFile.
 328  
      */
 329  
     private void setCurrentFile( ChangeFile currentFile )
 330  
     {
 331  4
         this.currentFile = currentFile;
 332  4
     }
 333  
 
 334  
     /**
 335  
      * Getter for property currentChange.
 336  
      *
 337  
      * @return Value of property currentChange.
 338  
      */
 339  
     private ChangeSet getCurrentChange()
 340  
     {
 341  16
         return currentChange;
 342  
     }
 343  
 
 344  
     /**
 345  
      * Setter for property currentChange.
 346  
      *
 347  
      * @param currentChange New value of property currentChange.
 348  
      */
 349  
     private void setCurrentChange( ChangeSet currentChange )
 350  
     {
 351  4
         this.currentChange = currentChange;
 352  4
     }
 353  
 
 354  
     /**
 355  
      * Getter for property status.
 356  
      *
 357  
      * @return Value of property status.
 358  
      */
 359  
     private int getStatus()
 360  
     {
 361  51
         return status;
 362  
     }
 363  
 
 364  
     /**
 365  
      * Setter for property status.
 366  
      *
 367  
      * @param status New value of property status.
 368  
      */
 369  
     private void setStatus( int status )
 370  
     {
 371  13
         this.status = status;
 372  13
     }
 373  
 }