0N/A/*
0N/A * CDDL HEADER START
0N/A *
0N/A * The contents of this file are subject to the terms of the
25N/A * Common Development and Distribution License (the "License").
0N/A * You may not use this file except in compliance with the License.
0N/A *
0N/A * See LICENSE.txt included in this distribution for the specific
0N/A * language governing permissions and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL HEADER in each
0N/A * file and include the License file at LICENSE.txt.
0N/A * If applicable, add the following below this CDDL HEADER, with the
0N/A * fields enclosed by brackets "[]" replaced with your own identifying
0N/A * information: Portions Copyright [yyyy] [name of copyright owner]
0N/A *
0N/A * CDDL HEADER END
0N/A */
0N/A
0N/A/*
176N/A * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
0N/A * Use is subject to license terms.
0N/A */
0N/Apackage org.opensolaris.opengrok.history;
0N/A
176N/Aimport java.io.BufferedReader;
176N/Aimport java.io.File;
176N/Aimport java.io.FileReader;
176N/Aimport java.io.IOException;
176N/Aimport java.util.ArrayList;
176N/Aimport java.util.Iterator;
176N/Aimport java.util.List;
176N/Aimport java.util.TreeMap;
427N/Aimport java.util.logging.Level;
1327N/Aimport java.util.logging.Logger;
1327N/A
176N/Aimport org.apache.commons.jrcs.rcs.Archive;
176N/Aimport org.apache.commons.jrcs.rcs.Node;
176N/Aimport org.apache.commons.jrcs.rcs.ParseException;
176N/Aimport org.apache.commons.jrcs.rcs.Version;
1195N/Aimport org.opensolaris.opengrok.util.IOUtils;
25N/A
0N/A
0N/A/**
0N/A * Virtualise RCS file as a reader, getting a specified version
0N/A */
770N/Aclass RCSHistoryParser {
25N/A
1473N/A private static final Logger logger =
1473N/A Logger.getLogger(RCSHistoryParser.class.getName());
1473N/A
1473N/A private static File readCVSRoot(File root, File CVSdir, String name)
1473N/A throws IOException
1473N/A {
588N/A String cvsroot = readFirstLine(root);
588N/A
588N/A if (cvsroot == null) {
588N/A return null;
588N/A }
588N/A if (cvsroot.charAt(0) != '/') {
588N/A return null;
588N/A }
588N/A
588N/A File repository = new File(CVSdir, "Repository");
588N/A String repo = readFirstLine(repository);
588N/A String dir = cvsroot + File.separatorChar + repo;
588N/A String filename = name + ",v";
588N/A File rcsFile = new File(dir, filename);
588N/A if (!rcsFile.exists()) {
588N/A File atticFile = new File(dir + File.separatorChar + "Attic", filename);
588N/A if (atticFile.exists()) {
588N/A rcsFile = atticFile;
588N/A }
588N/A }
588N/A return rcsFile;
588N/A }
588N/A
1473N/A History parse(File file) throws HistoryException {
615N/A try {
615N/A return parseFile(file);
615N/A } catch (IOException ioe) {
615N/A throw new HistoryException(ioe);
615N/A }
615N/A }
615N/A
615N/A private History parseFile(File file) throws IOException {
459N/A try {
459N/A Archive archive = new Archive(getRCSFile(file).getPath());
459N/A Version ver = archive.getRevisionVersion();
459N/A Node n = archive.findNode(ver);
459N/A n = n.root();
25N/A
459N/A ArrayList<HistoryEntry> entries = new ArrayList<HistoryEntry>();
459N/A traverse(n, entries);
56N/A
459N/A History history = new History();
459N/A history.setHistoryEntries(entries);
459N/A return history;
459N/A } catch (ParseException pe) {
1473N/A throw new IOException("Could not parse file '" + file.getPath()
1473N/A + "': " + pe.getMessage(), pe);
459N/A }
0N/A }
25N/A
25N/A private void traverse(Node n, List<HistoryEntry> history) {
154N/A if (n == null) {
0N/A return;
154N/A }
25N/A traverse(n.getChild(), history);
1182N/A TreeMap<?,?> brt = n.getBranches();
0N/A if (brt != null) {
1182N/A for (Iterator<?> i = brt.values().iterator(); i.hasNext();) {
0N/A Node b = (Node) i.next();
25N/A traverse(b, history);
0N/A }
0N/A }
154N/A if (!n.isGhost()) {
25N/A HistoryEntry entry = new HistoryEntry();
25N/A entry.setRevision(n.getVersion().toString());
25N/A entry.setDate(n.getDate());
25N/A entry.setAuthor(n.getAuthor());
25N/A entry.setMessage(n.getLog());
25N/A entry.setActive(true);
25N/A history.add(entry);
0N/A }
0N/A }
25N/A
154N/A protected static File getRCSFile(File file) {
154N/A return getRCSFile(file.getParent(), file.getName());
154N/A }
154N/A
154N/A protected static File getRCSFile(String parent, String name) {
154N/A File rcsDir = new File(parent, "RCS");
154N/A File rcsFile = new File(rcsDir, name + ",v");
154N/A if (rcsFile.exists()) {
154N/A return rcsFile;
154N/A }
154N/A // not RCS, try CVS instead
154N/A return getCVSFile(parent, name);
154N/A }
154N/A
154N/A protected static File getCVSFile(String parent, String name) {
154N/A try {
154N/A File CVSdir = new File(parent, "CVS");
154N/A if (CVSdir.isDirectory() && CVSdir.canRead()) {
154N/A File root = new File(CVSdir, "Root");
154N/A if (root.canRead()) {
588N/A return readCVSRoot(root, CVSdir, name);
154N/A }
154N/A }
154N/A } catch (Exception e) {
1327N/A logger.warning("Failed to retrieve CVS file of parent '" + parent
1327N/A + "', name '" + name + "': " + e.getMessage());
1327N/A logger.log(Level.FINE, "getCVSFile", e);
154N/A }
154N/A return null;
154N/A }
509N/A
509N/A /**
509N/A * Read the first line of a file.
509N/A * @param file the file from which to read
509N/A * @return the first line of the file, or {@code null} if the file is empty
509N/A * @throws IOException if an I/O error occurs while reading the file
509N/A */
1473N/A @SuppressWarnings("resource")
509N/A private static String readFirstLine(File file) throws IOException {
521N/A final BufferedReader in = new BufferedReader(new FileReader(file));
509N/A try {
521N/A return in.readLine();
509N/A } finally {
1195N/A IOUtils.close(in);
509N/A }
509N/A }
0N/A}