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  16
     private static Logger logger = Logger.getLogger(CvsFileBlockParser.class.getName());
 48  
     private final LookaheadReader logReader;
 49  
     private final CvsLogBuilder builder;
 50  100
     private boolean isLogWithoutSymbolicNames = false;
 51  
     private final boolean isFirstFile;
 52  100
     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  100
     public CvsFileBlockParser(final LookaheadReader logReader, final CvsLogBuilder builder, final boolean isFirstFile) {
 61  100
         this.logReader = logReader;
 62  100
         this.builder = builder;
 63  100
         this.isFirstFile = isFirstFile;
 64  100
     }
 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  100
         final String rcsFile = parseSingleLine(this.logReader.getCurrentLine(), "RCS file: ");
 74  100
         final String workingFile = parseSingleLine(this.logReader.nextLine(), "Working file: ");
 75  100
         final boolean isInAttic = CvsLogUtils.isInAttic(rcsFile, workingFile);
 76  100
         requireLine(this.logReader.nextLine(), "head:");
 77  100
         requireLine(this.logReader.nextLine(), "branch:");
 78  100
         requireLine(this.logReader.nextLine(), "locks:");
 79  100
         parseLocksAndAccessList();
 80  100
         parseSymbolicNames();
 81  100
         final String keywordSubst = parseSingleLine(this.logReader.getCurrentLine(), "keyword substitution: ");
 82  100
         boolean isBinary = false;
 83  
         try {
 84  100
             isBinary = CvsLogUtils.isBinaryKeywordSubst(keywordSubst);
 85  0
         } catch (final IllegalArgumentException unknownKeywordSubst) {
 86  0
             logger.warning("unknown keyword substitution '" + keywordSubst + "' in line " + this.logReader.getLineNumber());
 87  100
         }
 88  100
         requireLine(this.logReader.nextLine(), "total revisions:");
 89  100
         parseDescription();
 90  100
         if (this.isFirstFile) {
 91  32
             this.builder.buildModule(CvsLogUtils.getModuleName(rcsFile, workingFile));
 92  
         }
 93  100
         this.builder.buildFile(workingFile, isBinary, isInAttic, this.revBySymNames);
 94  100
         if (!CvsRevisionParser.FILE_DELIMITER.equals(this.logReader.getCurrentLine())) {
 95  92
             new CvsRevisionParser(this.logReader, this.builder).parse();
 96  
         }
 97  96
     }
 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  800
         if (!line.startsWith(lineStart)) {
 113  0
             throw new LogSyntaxException("line " + this.logReader.getLineNumber() + ": expected '" + lineStart + "' but found '" + line + "'");
 114  
         }
 115  
 
 116  800
         return line.substring(lineStart.length());
 117  
     }
 118  
 
 119  
     private void requireLine(final String line, final String lineStart) throws LogSyntaxException {
 120  
 
 121  500
         parseSingleLine(line, lineStart); // ignore this line
 122  500
     }
 123  
 
 124  
     private void parseSymbolicNames() throws IOException {
 125  100
         if (this.logReader.getCurrentLine().startsWith("keyword substitution: ")) {
 126  4
             return;
 127  
         }
 128  
         String line;
 129  96
         if (this.logReader.getCurrentLine().equals("symbolic names:")) {
 130  96
             line = this.logReader.nextLine();
 131  
         } else {
 132  0
             this.isLogWithoutSymbolicNames = true;
 133  0
             line = this.logReader.getCurrentLine();
 134  
         }
 135  112
         while (line != null && !line.startsWith("keyword substitution: ")) {
 136  16
             final int firstColon = line.indexOf(':');
 137  16
             final String tagName = line.substring(1, firstColon);
 138  16
             final String tagRevision = line.substring(firstColon + 2);
 139  16
             this.revBySymNames.put(tagName, tagRevision);
 140  16
             line = this.logReader.nextLine();
 141  16
         }
 142  96
     }
 143  
 
 144  
     private void parseLocksAndAccessList() throws IOException {
 145  108
         while (!"access list:".equals(this.logReader.nextLine())) {
 146  
             // ignore locks lines until "access list:" is reached
 147  
         }
 148  
         String line;
 149  
         do {
 150  108
             line = this.logReader.nextLine();
 151  
             // ignore access list lines until next section is reached
 152  108
         } while (!line.equals("symbolic names:") && !line.startsWith("keyword substitution: "));
 153  100
     }
 154  
 
 155  
     private void parseDescription() throws LogSyntaxException, IOException {
 156  100
         final String line = this.logReader.nextLine();
 157  100
         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  100
         requireLine(this.logReader.getCurrentLine(), "description:");
 161  124
         while (!isDescriptionDelimiter(this.logReader.nextLine())) {
 162  
             // ignore description lines
 163  
         }
 164  100
     }
 165  
 
 166  
     private boolean isDescriptionDelimiter(final String line) {
 167  124
         return CvsRevisionParser.REVISION_DELIMITER.equals(line) || CvsRevisionParser.FILE_DELIMITER.equals(line);
 168  
     }
 169  
 }