Coverage Report - net.sf.statcvs.input.CvsFileBlockParser
 
Classes in this File Line Coverage Branch Coverage Complexity
CvsFileBlockParser
89%
54/61
86%
24/28
2.556
 
 1  
 /*
 2  
     StatCvs - CVS statistics generation 
 3  
     Copyright (C) 2002  Lukasz Pekacki <lukasz@pekacki.de>
 4  
     http://statcvs.sf.net/
 5  
     
 6  
     This library is free software; you can redistribute it and/or
 7  
     modify it under the terms of the GNU Lesser General Public
 8  
     License as published by the Free Software Foundation; either
 9  
     version 2.1 of the License, or (at your option) any later version.
 10  
 
 11  
     This library is distributed in the hope that it will be useful,
 12  
     but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  
     Lesser General Public License for more details.
 15  
 
 16  
     You should have received a copy of the GNU Lesser General Public
 17  
     License along with this library; if not, write to the Free Software
 18  
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19  
     
 20  
         $RCSfile: CvsFileBlockParser.java,v $ 
 21  
         Created on $Date: 2008/04/02 11:22:15 $ 
 22  
 */
 23  
 
 24  
 package net.sf.statcvs.input;
 25  
 
 26  
 import java.io.IOException;
 27  
 import java.util.HashMap;
 28  
 import java.util.Map;
 29  
 import java.util.logging.Logger;
 30  
 
 31  
 import net.sf.statcvs.util.CvsLogUtils;
 32  
 import net.sf.statcvs.util.LookaheadReader;
 33  
 
 34  
 /**
 35  
  * Parses the information of one file from a CVS logfile
 36  
  * {@link net.sf.statcvs.util.LookaheadReader}. A {@link Builder} must be
 37  
  * specified which constructs some representation of that file. The lookahead
 38  
  * reader must be positioned on the first line of the file's section in the
 39  
  * log ("RCS file: ...").
 40  
  * 
 41  
  * @author Anja Jentzsch
 42  
  * @author Richard Cyganiak
 43  
  * @author Tammo van Lessen
 44  
  * @version $Id: CvsFileBlockParser.java,v 1.47 2008/04/02 11:22:15 benoitx Exp $
 45  
  */
 46  
 public class CvsFileBlockParser {
 47  24
     private static Logger logger = Logger.getLogger(CvsFileBlockParser.class.getName());
 48  
     private final LookaheadReader logReader;
 49  
     private final CvsLogBuilder builder;
 50  150
     private boolean isLogWithoutSymbolicNames = false;
 51  
     private final boolean isFirstFile;
 52  150
     private final Map revBySymNames = new HashMap();
 53  
 
 54  
     /**
 55  
      * Default Constructor CvsFileBlockParser.
 56  
      * @param logReader reader
 57  
      * @param builder a <tt>Builder</tt> for the creation process
 58  
      * @param isFirstFile Is this the first file of the log?
 59  
      */
 60  150
     public CvsFileBlockParser(final LookaheadReader logReader, final CvsLogBuilder builder, final boolean isFirstFile) {
 61  150
         this.logReader = logReader;
 62  150
         this.builder = builder;
 63  150
         this.isFirstFile = isFirstFile;
 64  150
     }
 65  
 
 66  
     /**
 67  
      * Parses one file from the input reader.
 68  
      * 
 69  
      * @throws LogSyntaxException on syntax error
 70  
      * @throws IOException on read/write error
 71  
      */
 72  
     public void parse() throws LogSyntaxException, IOException {
 73  150
         final String rcsFile = parseSingleLine(this.logReader.getCurrentLine(), "RCS file: ");
 74  150
         final String workingFile = parseSingleLine(this.logReader.nextLine(), "Working file: ");
 75  150
         final boolean isInAttic = CvsLogUtils.isInAttic(rcsFile, workingFile);
 76  150
         requireLine(this.logReader.nextLine(), "head:");
 77  150
         requireLine(this.logReader.nextLine(), "branch:");
 78  150
         requireLine(this.logReader.nextLine(), "locks:");
 79  150
         parseLocksAndAccessList();
 80  150
         parseSymbolicNames();
 81  150
         final String keywordSubst = parseSingleLine(this.logReader.getCurrentLine(), "keyword substitution: ");
 82  150
         boolean isBinary = false;
 83  
         try {
 84  150
             isBinary = CvsLogUtils.isBinaryKeywordSubst(keywordSubst);
 85  0
         } catch (final IllegalArgumentException unknownKeywordSubst) {
 86  0
             logger.warning("unknown keyword substitution '" + keywordSubst + "' in line " + this.logReader.getLineNumber());
 87  150
         }
 88  150
         requireLine(this.logReader.nextLine(), "total revisions:");
 89  150
         parseDescription();
 90  150
         if (this.isFirstFile) {
 91  48
             this.builder.buildModule(CvsLogUtils.getModuleName(rcsFile, workingFile));
 92  
         }
 93  150
         this.builder.buildFile(workingFile, isBinary, isInAttic, this.revBySymNames);
 94  150
         if (!CvsRevisionParser.FILE_DELIMITER.equals(this.logReader.getCurrentLine())) {
 95  138
             new CvsRevisionParser(this.logReader, this.builder).parse();
 96  
         }
 97  144
     }
 98  
 
 99  
     /**
 100  
      * Returns <tt>true</tt> if the log was generated
 101  
      * with the "-N" switch of "cvs log"
 102  
      * 
 103  
      * @return Returns <tt>true</tt> if the log was generated
 104  
      * with the "-N" switch of "cvs log"
 105  
      */
 106  
     public boolean isLogWithoutSymbolicNames() {
 107  0
         return this.isLogWithoutSymbolicNames;
 108  
     }
 109  
 
 110  
     private String parseSingleLine(final String line, final String lineStart) throws LogSyntaxException {
 111  
 
 112  1200
         if (!line.startsWith(lineStart)) {
 113  0
             throw new LogSyntaxException("line " + this.logReader.getLineNumber() + ": expected '" + lineStart + "' but found '" + line + "'");
 114  
         }
 115  
 
 116  1200
         return line.substring(lineStart.length());
 117  
     }
 118  
 
 119  
     private void requireLine(final String line, final String lineStart) throws LogSyntaxException {
 120  
 
 121  750
         parseSingleLine(line, lineStart); // ignore this line
 122  750
     }
 123  
 
 124  
     private void parseSymbolicNames() throws IOException {
 125  150
         if (this.logReader.getCurrentLine().startsWith("keyword substitution: ")) {
 126  6
             return;
 127  
         }
 128  
         String line;
 129  144
         if (this.logReader.getCurrentLine().equals("symbolic names:")) {
 130  144
             line = this.logReader.nextLine();
 131  
         } else {
 132  0
             this.isLogWithoutSymbolicNames = true;
 133  0
             line = this.logReader.getCurrentLine();
 134  
         }
 135  168
         while (line != null && !line.startsWith("keyword substitution: ")) {
 136  24
             final int firstColon = line.indexOf(':');
 137  24
             final String tagName = line.substring(1, firstColon);
 138  24
             final String tagRevision = line.substring(firstColon + 2);
 139  24
             this.revBySymNames.put(tagName, tagRevision);
 140  24
             line = this.logReader.nextLine();
 141  20
         }
 142  144
     }
 143  
 
 144  
     private void parseLocksAndAccessList() throws IOException {
 145  162
         while (!"access list:".equals(this.logReader.nextLine())) {
 146  
             // ignore locks lines until "access list:" is reached
 147  
         }
 148  
         String line;
 149  
         do {
 150  162
             line = this.logReader.nextLine();
 151  
             // ignore access list lines until next section is reached
 152  162
         } while (!line.equals("symbolic names:") && !line.startsWith("keyword substitution: "));
 153  150
     }
 154  
 
 155  
     private void parseDescription() throws LogSyntaxException, IOException {
 156  150
         final String line = this.logReader.nextLine();
 157  150
         if (line.equals(CvsRevisionParser.FILE_DELIMITER)) {
 158  0
             throw new LogSyntaxException("line " + this.logReader.getLineNumber() + ": missing description; please don't use the -h switch of 'cvs log'!");
 159  
         }
 160  150
         requireLine(this.logReader.getCurrentLine(), "description:");
 161  186
         while (!isDescriptionDelimiter(this.logReader.nextLine())) {
 162  
             // ignore description lines
 163  
         }
 164  150
     }
 165  
 
 166  
     private boolean isDescriptionDelimiter(final String line) {
 167  186
         return CvsRevisionParser.REVISION_DELIMITER.equals(line) || CvsRevisionParser.FILE_DELIMITER.equals(line);
 168  
     }
 169  
 }