823N/A/*
823N/A * CDDL HEADER START
823N/A *
823N/A * The contents of this file are subject to the terms of the
823N/A * Common Development and Distribution License (the "License").
823N/A * You may not use this file except in compliance with the License.
823N/A *
823N/A * See LICENSE.txt included in this distribution for the specific
823N/A * language governing permissions and limitations under the License.
823N/A *
823N/A * When distributing Covered Code, include this CDDL HEADER in each
823N/A * file and include the License file at LICENSE.txt.
823N/A * If applicable, add the following below this CDDL HEADER, with the
823N/A * fields enclosed by brackets "[]" replaced with your own identifying
823N/A * information: Portions Copyright [yyyy] [name of copyright owner]
823N/A *
823N/A * CDDL HEADER END
823N/A */
823N/A
823N/A/*
823N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
823N/A * Use is subject to license terms.
823N/A */
823N/Apackage org.opensolaris.opengrok.history;
823N/A
823N/Aimport java.io.BufferedReader;
823N/Aimport java.io.File;
1016N/Aimport java.io.FileNotFoundException;
823N/Aimport java.io.IOException;
823N/Aimport java.io.InputStream;
823N/Aimport java.io.InputStreamReader;
823N/Aimport java.text.DateFormat;
823N/Aimport java.text.ParseException;
823N/Aimport java.util.ArrayList;
823N/Aimport java.util.Date;
823N/Aimport java.util.List;
823N/Aimport java.util.logging.Level;
823N/Aimport org.opensolaris.opengrok.OpenGrokLogger;
823N/Aimport org.opensolaris.opengrok.configuration.RuntimeEnvironment;
823N/Aimport org.opensolaris.opengrok.util.Executor;
823N/A
823N/A/**
823N/A * Class used to parse the history log from Monotone
1190N/A *
823N/A * @author Trond Norbye
823N/A */
823N/Aclass MonotoneHistoryParser implements Executor.StreamHandler {
823N/A
860N/A private List<HistoryEntry> entries = new ArrayList<HistoryEntry>(); //NOPMD
823N/A private final MonotoneRepository repository;
823N/A private final String mydir;
823N/A
823N/A MonotoneHistoryParser(MonotoneRepository repository) {
823N/A this.repository = repository;
823N/A mydir = repository.getDirectoryName() + File.separator;
823N/A }
823N/A
823N/A /**
823N/A * Parse the history for the specified file or directory. If a changeset is
823N/A * specified, only return the history from the changeset right after the
823N/A * specified one.
823N/A *
823N/A * @param file the file or directory to get history for
823N/A * @param changeset the changeset right before the first one to fetch, or
823N/A * {@code null} if all changesets should be fetched
823N/A * @return history for the specified file or directory
823N/A * @throws HistoryException if an error happens when parsing the history
823N/A */
823N/A History parse(File file, String changeset) throws HistoryException {
1016N/A try {
1016N/A Executor executor = repository.getHistoryLogExecutor(file, changeset);
1016N/A int status = executor.exec(true, this);
1190N/A
1016N/A if (status != 0) {
1016N/A throw new HistoryException("Failed to get history for: \"" +
1016N/A file.getAbsolutePath() + "\" Exit code: " + status);
1016N/A }
1016N/A } catch (IOException e) {
823N/A throw new HistoryException("Failed to get history for: \"" +
1016N/A file.getAbsolutePath() + "\"", e);
823N/A }
823N/A
823N/A return new History(entries);
823N/A }
823N/A
823N/A /**
823N/A * Process the output from the hg log command and insert the HistoryEntries
823N/A * into the history field.
823N/A *
823N/A * @param input The output from the process
823N/A * @throws java.io.IOException If an error occurs while reading the stream
823N/A */
823N/A @Override
823N/A public void processStream(InputStream input) throws IOException {
1016N/A RuntimeEnvironment env = RuntimeEnvironment.getInstance();
823N/A DateFormat df = repository.getDateFormat();
823N/A BufferedReader in = new BufferedReader(new InputStreamReader(input));
823N/A String s;
823N/A
823N/A HistoryEntry entry = null;
823N/A int state = 0;
823N/A while ((s = in.readLine()) != null) {
823N/A s = s.trim();
1380N/A // Later versions of monotone (such as 1.0) output even more dashes so lets require
1380N/A // the minimum amount for maximum compatibility between monotone versions.
1380N/A if (s.startsWith("-----------------------------------------------------------------")) {
823N/A if (entry != null && state > 2) {
823N/A entries.add(entry);
823N/A }
823N/A entry = new HistoryEntry();
823N/A entry.setActive(true);
823N/A state = 0;
823N/A
823N/A continue;
823N/A }
823N/A
823N/A switch (state) {
823N/A case 0:
823N/A if (s.startsWith("Revision:")) {
823N/A String rev = s.substring("Revision:".length()).trim();
823N/A entry.setRevision(rev);
823N/A ++state;
823N/A }
823N/A break;
823N/A case 1:
823N/A if (s.startsWith("Author:")) {
823N/A entry.setAuthor(s.substring("Author:".length()).trim());
823N/A ++state;
823N/A }
823N/A break;
823N/A case 2:
823N/A if (s.startsWith("Date:")) {
823N/A Date date = new Date();
823N/A try {
823N/A date = df.parse(s.substring("date:".length()).trim());
823N/A } catch (ParseException pe) {
823N/A OpenGrokLogger.getLogger().log(Level.WARNING, "Could not parse date: " + s, pe);
823N/A }
823N/A entry.setDate(date);
823N/A ++state;
823N/A }
823N/A break;
823N/A case 3:
823N/A if (s.startsWith("Modified ") || s.startsWith("Added ") || s.startsWith("Deleted ")) {
823N/A ++state;
823N/A } else if (s.equalsIgnoreCase("ChangeLog:")) {
823N/A state = 5;
823N/A }
823N/A break;
823N/A case 4:
860N/A if (s.startsWith("Modified ") || s.startsWith("Added ") || s.startsWith("Deleted ")) { //NOPMD
823N/A /* swallow */
823N/A } else if (s.equalsIgnoreCase("ChangeLog:")) {
823N/A state = 5;
823N/A } else {
823N/A String files[] = s.split(" ");
823N/A for (String f : files) {
823N/A File file = new File(mydir, f);
1016N/A try {
1016N/A entry.addFile(env.getPathRelativeToSourceRoot(file, 0));
1016N/A } catch (FileNotFoundException e) { // NOPMD
1016N/A // If the file is not located under the source root, ignore it
1016N/A }
823N/A }
823N/A }
823N/A break;
823N/A case 5:
823N/A entry.appendMessage(s);
823N/A break;
823N/A default:
823N/A OpenGrokLogger.getLogger().warning("Unknown parser state: " + state);
823N/A break;
823N/A }
823N/A }
823N/A
823N/A if (entry != null && state > 2) {
823N/A entries.add(entry);
823N/A }
823N/A }
823N/A}