Coverage Report - org.apache.maven.scm.provider.perforce.command.changelog.PerforceDescribeConsumer
 
Classes in this File Line Coverage Branch Coverage Complexity
PerforceDescribeConsumer
89 %
51/57
76 %
16/21
3,375
 
 1  
 package org.apache.maven.scm.provider.perforce.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 java.util.ArrayList;
 23  
 import java.util.List;
 24  
 
 25  
 import org.apache.maven.scm.ChangeFile;
 26  
 import org.apache.maven.scm.ChangeSet;
 27  
 import org.apache.maven.scm.ScmException;
 28  
 import org.apache.maven.scm.log.ScmLogger;
 29  
 import org.apache.maven.scm.util.AbstractConsumer;
 30  
 import org.apache.regexp.RE;
 31  
 import org.apache.regexp.RESyntaxException;
 32  
 
 33  
 /**
 34  
  * Parse the tagged output from "p4 describe -s [change] [change] [...]".
 35  
  *
 36  
  * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
 37  
  * @author Olivier Lamy
 38  
  * @version $Id: PerforceDescribeConsumer.java 1054408 2011-01-02 14:05:25Z olamy $
 39  
  */
 40  
 public class PerforceDescribeConsumer
 41  
     extends AbstractConsumer
 42  
 {
 43  
     
 44  1
     private List<ChangeSet> entries = new ArrayList<ChangeSet>();
 45  
 
 46  
     /**
 47  
      * State machine constant: expecting revision
 48  
      */
 49  
     private static final int GET_REVISION = 1;
 50  
 
 51  
     /**
 52  
      * State machine constant: eat the first blank line
 53  
      */
 54  
     private static final int GET_COMMENT_BEGIN = 2;
 55  
 
 56  
     /**
 57  
      * State machine constant: expecting comments
 58  
      */
 59  
     private static final int GET_COMMENT = 3;
 60  
 
 61  
     /**
 62  
      * State machine constant: expecting "Affected files"
 63  
      */
 64  
     private static final int GET_AFFECTED_FILES = 4;
 65  
 
 66  
     /**
 67  
      * State machine constant: expecting blank line
 68  
      */
 69  
     private static final int GET_FILES_BEGIN = 5;
 70  
 
 71  
     /**
 72  
      * State machine constant: expecting files
 73  
      */
 74  
     private static final int GET_FILE = 6;
 75  
 
 76  
     /**
 77  
      * Current status of the parser
 78  
      */
 79  1
     private int status = GET_REVISION;
 80  
 
 81  
     /**
 82  
      * The current log entry being processed by the parser
 83  
      */
 84  
     @SuppressWarnings( "unused" )
 85  
     private String currentRevision;
 86  
 
 87  
     /**
 88  
      * The current log entry being processed by the parser
 89  
      */
 90  
     private ChangeSet currentChange;
 91  
 
 92  
     /**
 93  
      * the current file being processed by the parser
 94  
      */
 95  
     private String currentFile;
 96  
 
 97  
     /**
 98  
      * The location of files within the Perforce depot that we are processing
 99  
      * e.g. //depot/projects/foo/bar
 100  
      */
 101  
     private String repoPath;
 102  
 
 103  
     private String userDatePattern;
 104  
 
 105  
     private static final String REVISION_PATTERN = "^Change (\\d+) " + // changelist number
 106  
         "by (.*)@[^ ]+ " + // author
 107  
         "on (.*)"; // date
 108  
     /**
 109  
      * The comment section ends with a blank line
 110  
      */
 111  
     private static final String COMMENT_DELIMITER = "";
 112  
     /**
 113  
      * The changelist ends with a blank line
 114  
      */
 115  
     private static final String CHANGELIST_DELIMITER = "";
 116  
 
 117  
     private static final String FILE_PATTERN = "^\\.\\.\\. (.*)#(\\d+) ";
 118  
 
 119  
     /**
 120  
      * The regular expression used to match header lines
 121  
      */
 122  
     private RE revisionRegexp;
 123  
 
 124  
     /**
 125  
      * The regular expression used to match file paths
 126  
      */
 127  
     private RE fileRegexp;
 128  
 
 129  
     public PerforceDescribeConsumer( String repoPath, String userDatePattern, ScmLogger logger )
 130  
     {
 131  1
         super( logger );
 132  
 
 133  1
         this.repoPath = repoPath;
 134  1
         this.userDatePattern = userDatePattern;
 135  
 
 136  
         try
 137  
         {
 138  1
             revisionRegexp = new RE( REVISION_PATTERN );
 139  1
             fileRegexp = new RE( FILE_PATTERN );
 140  
         }
 141  0
         catch ( RESyntaxException ignored )
 142  
         {
 143  0
             if ( getLogger().isErrorEnabled() )
 144  
             {
 145  0
                 getLogger().error( "Could not create regexps to parse Perforce descriptions", ignored );
 146  
             }
 147  1
         }
 148  1
     }
 149  
 
 150  
     // ----------------------------------------------------------------------
 151  
     //
 152  
     // ----------------------------------------------------------------------
 153  
 
 154  
     public List<ChangeSet> getModifications() throws ScmException
 155  
     {
 156  1
         return entries;
 157  
     }
 158  
 
 159  
     // ----------------------------------------------------------------------
 160  
     // StreamConsumer Implementation
 161  
     // ----------------------------------------------------------------------
 162  
 
 163  
     /** {@inheritDoc} */
 164  
     public void consumeLine( String line )
 165  
     {
 166  69
         switch ( status )
 167  
         {
 168  
             case GET_REVISION:
 169  7
                 processGetRevision( line );
 170  7
                 break;
 171  
             case GET_COMMENT_BEGIN:
 172  7
                 status = GET_COMMENT;
 173  7
                 break;
 174  
             case GET_COMMENT:
 175  18
                 processGetComment( line );
 176  18
                 break;
 177  
             case GET_AFFECTED_FILES:
 178  13
                 processGetAffectedFiles( line );
 179  13
                 break;
 180  
             case GET_FILES_BEGIN:
 181  7
                 status = GET_FILE;
 182  7
                 break;
 183  
             case GET_FILE:
 184  17
                 processGetFile( line );
 185  17
                 break;
 186  
             default:
 187  0
                 throw new IllegalStateException( "Unknown state: " + status );
 188  
         }
 189  69
     }
 190  
 
 191  
     // ----------------------------------------------------------------------
 192  
     //
 193  
     // ----------------------------------------------------------------------
 194  
 
 195  
     /**
 196  
      * Add a change log entry to the list (if it's not already there)
 197  
      * with the given file.
 198  
      *
 199  
      * @param entry a {@link ChangeSet} to be added to the list if another
 200  
      *              with the same key (p4 change number) doesn't exist already.
 201  
      * @param file  a {@link ChangeFile} to be added to the entry
 202  
      */
 203  
     private void addEntry( ChangeSet entry, ChangeFile file )
 204  
     {
 205  9
         entry.addFile( file );
 206  9
     }
 207  
 
 208  
     /**
 209  
      * Each file matches the fileRegexp.
 210  
      *
 211  
      * @param line A line of text from the Perforce log output
 212  
      */
 213  
     private void processGetFile( String line )
 214  
     {
 215  17
         if ( line.equals( CHANGELIST_DELIMITER ) ) {
 216  7
             entries.add( 0, currentChange );
 217  7
             status = GET_REVISION;
 218  7
             return;
 219  
         }
 220  10
         if ( !fileRegexp.match( line ) )
 221  
         {
 222  0
             return;
 223  
         }
 224  
 
 225  10
         currentFile = fileRegexp.getParen( 1 );
 226  
 
 227  
         // Although Perforce allows files to be submitted anywhere in the
 228  
         // repository in a single changelist, we're only concerned about the
 229  
         // local files.
 230  10
         if( currentFile.startsWith( repoPath ) ) {
 231  9
             currentFile = currentFile.substring( repoPath.length() + 1 );
 232  9
             addEntry( currentChange, new ChangeFile( currentFile, fileRegexp.getParen( 2 ) ) );
 233  
         }
 234  10
     }
 235  
 
 236  
     /**
 237  
      * Most of the relevant info is on the revision line matching the
 238  
      * 'pattern' string.
 239  
      *
 240  
      * @param line A line of text from the perforce log output
 241  
      */
 242  
     private void processGetRevision( String line )
 243  
     {
 244  7
         if ( !revisionRegexp.match( line ) )
 245  
         {
 246  0
             return;
 247  
         }
 248  7
         currentChange = new ChangeSet();
 249  7
         currentRevision = revisionRegexp.getParen( 1 );
 250  7
         currentChange.setAuthor( revisionRegexp.getParen( 2 ) );
 251  7
         currentChange.setDate( revisionRegexp.getParen( 3 ), userDatePattern );
 252  
 
 253  7
         status = GET_COMMENT_BEGIN;
 254  7
     }
 255  
 
 256  
     /**
 257  
      * Process the current input line in the GET_COMMENT state.  This
 258  
      * state gathers all of the comments that are part of a log entry.
 259  
      *
 260  
      * @param line a line of text from the perforce log output
 261  
      */
 262  
     private void processGetComment( String line )
 263  
     {
 264  18
         if ( line.equals( COMMENT_DELIMITER ) )
 265  
         {
 266  7
             status = GET_AFFECTED_FILES;
 267  
         }
 268  
         else
 269  
         {
 270  
             // remove prepended tab
 271  11
             currentChange.setComment( currentChange.getComment() + line.substring(1) + "\n" );
 272  
         }
 273  18
     }
 274  
 
 275  
     /**
 276  
      * Process the current input line in the GET_COMMENT state.  This
 277  
      * state gathers all of the comments that are part of a log entry.
 278  
      *
 279  
      * @param line a line of text from the perforce log output
 280  
      */
 281  
     private void processGetAffectedFiles( String line )
 282  
     {
 283  13
         if ( !line.equals( "Affected files ..." ) )
 284  
         {
 285  6
             return;
 286  
         }
 287  7
         status = GET_FILES_BEGIN;
 288  7
     }
 289  
 }