Skip to content

Commit d294908

Browse files
committed
Support for Surround SCM history
1 parent 80c87d7 commit d294908

File tree

3 files changed

+528
-0
lines changed

3 files changed

+528
-0
lines changed

src/org/opensolaris/opengrok/history/RepositoryFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public final class RepositoryFactory {
5353
new RCSRepository(),
5454
new CVSRepository(),
5555
new RepoRepository(),
56+
new SSCMRepository(),
5657
};
5758

5859
private RepositoryFactory() {
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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+
package org.opensolaris.opengrok.history;
21+
22+
import java.io.BufferedReader;
23+
import java.io.File;
24+
import java.io.IOException;
25+
import java.io.InputStream;
26+
import java.io.InputStreamReader;
27+
import java.text.DateFormat;
28+
import java.text.ParseException;
29+
import java.util.ArrayList;
30+
import java.util.logging.Level;
31+
import java.util.regex.Matcher;
32+
import java.util.regex.Pattern;
33+
import org.opensolaris.opengrok.OpenGrokLogger;
34+
import org.opensolaris.opengrok.util.Executor;
35+
36+
/**
37+
*
38+
* @author michailf
39+
*/
40+
public class SSCMHistoryParser implements Executor.StreamHandler {
41+
42+
private final SSCMRepository repository;
43+
44+
SSCMHistoryParser(SSCMRepository repository) {
45+
this.repository = repository;
46+
}
47+
48+
private static final String FILTER_ACTION_PATTERN = "^add to branch$";
49+
private static final String ACTION_PATTERN = "[a-z ]+";
50+
private static final String USER_PATTERN = "\\w+";
51+
private static final String VERSION_PATTERN = "\\d+";
52+
private static final String TIME_PATTERN = "\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{2} [AP]M";
53+
private static final String COMMENT_START_PATTERN = "Comments - ";
54+
// ^([a-z ]+)(?:\[.*?\])?\s+(\w+)\s+(\d+)\s+(\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{2} [AP]M)$\s*(?:Comments - )?
55+
private static final Pattern HISTORY_PATTERN = Pattern.compile("^(" + ACTION_PATTERN + ")(?:\\[(.*?)\\])?\\s+(" + USER_PATTERN + ")\\s+(" + VERSION_PATTERN + ")\\s+(" + TIME_PATTERN + ")$\\s*(?:" + COMMENT_START_PATTERN + ")?",
56+
Pattern.MULTILINE);
57+
58+
private static final String NEWLINE = System.getProperty("line.separator");
59+
60+
private History history;
61+
62+
@Override
63+
public void processStream(InputStream input) throws IOException {
64+
DateFormat df = repository.getDateFormat();
65+
history = new History();
66+
67+
BufferedReader in = new BufferedReader(new InputStreamReader(input));
68+
StringBuilder total = new StringBuilder(input.available());
69+
String line;
70+
while ((line = in.readLine()) != null) {
71+
total.append(line).append(NEWLINE);
72+
}
73+
74+
ArrayList<HistoryEntry> entries = new ArrayList<>();
75+
HistoryEntry entry = null;
76+
int prevEntryEnd = 0;
77+
78+
long revisionCounter = 0;
79+
Matcher matcher = HISTORY_PATTERN.matcher(total);
80+
while (matcher.find()) {
81+
if (entry != null) {
82+
if (matcher.start() != prevEntryEnd) {
83+
// Get the comment and reduce all double new lines to single
84+
// add a space as well for better formatting in RSS feeds.
85+
entry.appendMessage(total.substring(prevEntryEnd, matcher.start()).replaceAll("(\\r?\\n){2}", " $1").trim());
86+
}
87+
entries.add(0, entry);
88+
entry = null;
89+
}
90+
if (!matcher.group(1).matches(FILTER_ACTION_PATTERN)) {
91+
String revision = matcher.group(4);
92+
String author = matcher.group(3);
93+
String branch = matcher.group(2);
94+
95+
long currentRevision = Long.parseLong(revision);
96+
if (revisionCounter < currentRevision) {
97+
revisionCounter = currentRevision;
98+
99+
entry = new HistoryEntry();
100+
// Add branch name to message. Helps when branch name is used
101+
// as indicator of why promote was made.
102+
if (branch != null)
103+
entry.appendMessage("[" + branch + "] ");
104+
entry.setAuthor(author);
105+
entry.setRevision(revision);
106+
try {
107+
entry.setDate(df.parse(matcher.group(5)));
108+
} catch (ParseException ex) {
109+
OpenGrokLogger.getLogger().log(Level.WARNING, "Failed to parse date: '" + matcher.group(5) + "'", ex);
110+
}
111+
entry.setActive(true);
112+
}
113+
}
114+
prevEntryEnd = matcher.end();
115+
}
116+
117+
if (entry != null) {
118+
if (total.length() != prevEntryEnd) {
119+
// Get the comment and reduce all double new lines to single
120+
// add a space as well for better formatting in RSS feeds.
121+
entry.appendMessage(total.substring(prevEntryEnd).replaceAll("(\\r?\\n){2}", " $1").trim());
122+
}
123+
entries.add(0, entry);
124+
}
125+
history.setHistoryEntries(entries);
126+
}
127+
128+
History parse(File file, String sinceRevision) throws HistoryException {
129+
try {
130+
Executor executor = repository.getHistoryLogExecutor(file, sinceRevision);
131+
int status = executor.exec(true, this);
132+
133+
if (status != 0) {
134+
throw new HistoryException("Failed to get history for: \"" +
135+
file.getAbsolutePath() + "\" Exit code: " + status);
136+
}
137+
} catch (IOException e) {
138+
throw new HistoryException("Failed to get history for: \"" +
139+
file.getAbsolutePath() + "\"", e);
140+
}
141+
142+
return history;
143+
}
144+
}

0 commit comments

Comments
 (0)