/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * See LICENSE.txt included in this distribution for the specific * language governing permissions and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at LICENSE.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ package org.opensolaris.opengrok.history; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Locale; import java.util.logging.Logger; import org.opensolaris.opengrok.util.IOUtils; /** * Reads and filters out junk from a SCCS history file * see sccsfile(4) for details of the file format * Wrote it since invoking sccs prs for each file was * taking a lot of time. Time to index history has reduced 4 to 1! */ class SCCSHistoryParser { private static final Logger logger = Logger.getLogger(SCCSHistoryParser.class.getName()); boolean pass; boolean passRecord; boolean active; int field; boolean sep; StringBuilder record = new StringBuilder(128); private String revision; private String author; private Date rdate; private String comment; DateFormat sccsDateFormat; Reader in; History parse(File file, Repository repos) throws HistoryException { sccsDateFormat = repos.getDateFormat(); try { return parseFile(file); } catch (IOException ioe) { throw new HistoryException(ioe); } } private History parseFile(File file) throws IOException { File f = getSCCSFile(file); if (f == null) { return null; } in = new BufferedReader(new FileReader(getSCCSFile(file))); pass = sep = false; passRecord = true; active = true; field = 0; sccsDateFormat = new SimpleDateFormat("yy/MM/dd", Locale.getDefault()); ArrayList entries = new ArrayList(); while (next()) { HistoryEntry entry = new HistoryEntry(); entry.setRevision(getRevision()); entry.setDate(getDate()); entry.setAuthor(getAuthor()); entry.setMessage(getComment()); entry.setActive(isActive()); entries.add(entry); } IOUtils.close(in); History history = new History(); history.setHistoryEntries(entries); return history; } /** * Read a single line of delta record * * @throws java.io.IOException * @return a String representing a single log delta entry * rev date time author comments(s) */ private boolean next() throws java.io.IOException { sep = true; record.setLength(0); int c; while ((c = read()) > 01) { record.append((char)c); } // to flag that revision needs to be re populated if you really need it revision = null; return (record.length() > 2); } private void initFields() { if(revision == null) { String[] f = record.toString().split(" ", 6); if (f.length > 5) { revision = f[1]; try { rdate = sccsDateFormat.parse(f[2] + " " + f[3]); } catch (ParseException e) { logger.warning("An error occured while parsing date: " + e.getMessage()); rdate = null; } author = f[4]; comment = f[5]; } else { rdate = null; author = null; comment = null; } } } /** * @return get the revision string of current log record */ private String getRevision() { initFields(); return revision; } /** * @return get the date assosiated with current log record */ private Date getDate() { initFields(); return rdate; } /** * @return get the author of current log record */ private String getAuthor() { initFields(); return author; } /** * @return get the comments of current log record */ private String getComment() { initFields(); return comment; } private boolean isActive() { return active; } private int read() throws java.io.IOException { int c, d, dt; while((c = in.read()) != -1) { switch (c) { //NOPMD case 01: d = in.read(); switch (d) { case 'c': case 't': case 'u': d = in.read(); if(d != ' ') { return (d); } pass = true; break; case 'd': d = in.read(); if (d == ' ') { dt = in.read(); if (dt == 'R') { active = false; } else { active = true; } passRecord = true; field = 1; } else { return (d); } break; case -1: case 'I': //the file contents start case 'D': case 'E': case 'T': return(-1); case 'e': pass = false; if (sep && passRecord) { return 01; } passRecord = true; break; default: pass = false; } break; case ' ': if (passRecord) { if (field > 0) { field ++; pass = true; } if(field > 5) { field = 0; pass = false; return(c); } } default: if (pass && passRecord) { return(c); } } } return(-1); } protected static File getSCCSFile(File file) { return getSCCSFile(file.getParent(), file.getName()); } protected static File getSCCSFile(String parent, String name) { File f = new File(parent + "/SCCS/s." + name); if (!f.exists()) { return null; } return f; } }