1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * See LICENSE.txt included in this distribution for the specific 9 * language governing permissions and limitations under the License. 10 * 11 * When distributing Covered Code, include this CDDL HEADER in each 12 * file and include the License file at LICENSE.txt. 13 * If applicable, add the following below this CDDL HEADER, with the 14 * fields enclosed by brackets "[]" replaced with your own identifying 15 * information: Portions Copyright [yyyy] [name of copyright owner] 16 * 17 * CDDL HEADER END 18 */ 19 20 /* 21 * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. 22 */ 23 package org.opengrok.indexer.history; 24 25 import java.io.BufferedReader; 26 import java.io.File; 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.io.InputStreamReader; 30 import java.text.ParseException; 31 import java.util.ArrayList; 32 import java.util.Date; 33 import java.util.List; 34 import org.opengrok.indexer.util.Executor; 35 36 /** 37 * Parse source history for a AccuRev Repository. 38 * 39 * @author Steven Haehn 40 */ 41 public class AccuRevHistoryParser implements Executor.StreamHandler { 42 43 private AccuRevRepository repository; 44 private History history; 45 46 /** 47 * Parse the history for the specified file. 48 * 49 * @param file the file to parse history for 50 * @param repos Pointer to the {@code AccuRevRepository} 51 * @return object representing the file's history 52 * @throws HistoryException if a problem occurs while executing p4 command 53 */ parse(File file, Repository repos)54 History parse(File file, Repository repos) throws HistoryException { 55 56 repository = (AccuRevRepository) repos; 57 58 history = null; 59 60 String relPath = repository.getDepotRelativePath(file); 61 62 /* 63 * When the path given is really just the root to the source 64 * workarea, no history is available, create fake. 65 */ 66 67 String rootRelativePath = File.separator + "." + File.separator; 68 69 if (relPath.equals(rootRelativePath)) { 70 71 List<HistoryEntry> entries = new ArrayList<>(); 72 73 entries.add(new HistoryEntry( 74 "", new Date(), "OpenGrok", "Workspace Root", true)); 75 76 history = new History(entries); 77 78 } else { 79 try { 80 /* 81 * Errors will be logged, so not bothering to add to the output. 82 */ 83 Executor executor = repository.getHistoryLogExecutor(file); 84 executor.exec(true, this); 85 86 } catch (IOException e) { 87 throw new HistoryException( 88 "Failed to get history for: \"" 89 + file.getAbsolutePath() + "\"" + e); 90 } 91 } 92 93 return history; 94 } 95 96 @Override processStream(InputStream input)97 public void processStream(InputStream input) throws IOException { 98 99 BufferedReader in = new BufferedReader(new InputStreamReader(input)); 100 List<HistoryEntry> entries = new ArrayList<>(); 101 String line; 102 String user; 103 Date date; 104 HistoryEntry entry = null; 105 106 history = new History(); 107 108 /* 109 * Accurev history of an element (directory or file) looks like: 110 * 111 * element: /./path/to/element eid: 238865 transaction 1486194; purge; 112 * 2012/02/28 12:46:55 ; user: tluksha version 2541/1 (2539/1) 113 * 114 * transaction 1476285; purge; 2012/02/03 12:16:25 ; user: shaehn 115 * version 4241/1 (4241/1) 116 * 117 * transaction 1317224; promote; 2011/05/03 11:37:56 ; user: mtrinh # 118 * changes to ngb to compile on windows version 13/93 (1000/2) 119 * 120 * ... 121 * 122 * What is of interest then is: user (author), version (revision), date, 123 * comment (message) 124 * 125 * Any lines not recognized are ignored. 126 */ 127 while ((line = in.readLine()) != null) { 128 129 if (line.startsWith("e")) { 130 continue; 131 } // ignore element, eid 132 133 if (line.startsWith("t")) { // found transaction 134 135 String[] data = line.split("; "); 136 entry = new HistoryEntry(); 137 138 user = data[3].replaceFirst("user: ", ""); 139 140 entry.setMessage(""); 141 entry.setAuthor(user); 142 143 try { 144 date = repository.parse(data[2]); 145 entry.setDate(date); 146 } catch (ParseException pe) { 147 // 148 // Overriding processStream() thus need to comply with the 149 // set of exceptions it can throw. 150 // 151 throw new IOException("Could not parse date: " + line, pe); 152 } 153 154 } else if (line.startsWith(" #")) { // found comment 155 156 entry.appendMessage(line.substring(3)); 157 158 } else if (line.startsWith(" v")) { // found version 159 160 String[] data = line.split("\\s+"); 161 entry.setRevision(data[2]); 162 entry.setActive(true); 163 entries.add(entry); 164 } 165 } 166 167 history.setHistoryEntries(entries); 168 } 169 } 170