Skip to content

Commit 794d0b7

Browse files
committed
convert Mercurial to RepositoryWithHistoryTraversal
1 parent 516b9eb commit 794d0b7

File tree

7 files changed

+187
-117
lines changed

7 files changed

+187
-117
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/history/GitRepository.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -475,27 +475,6 @@ public History getHistory(File file, String sinceRevision, String tillRevision)
475475
return getHistory(file, sinceRevision, tillRevision, null);
476476
}
477477

478-
public History getHistory(File file, String sinceRevision, String tillRevision,
479-
Integer numCommits) throws HistoryException {
480-
481-
if (numCommits != null && numCommits <= 0) {
482-
return null;
483-
}
484-
485-
HistoryCollector historyCollector = new HistoryCollector(isMergeCommitsEnabled());
486-
traverseHistory(file, sinceRevision, tillRevision, numCommits, List.of(historyCollector));
487-
History history = new History(historyCollector.entries, historyCollector.renamedFiles);
488-
489-
// Assign tags to changesets they represent
490-
// We don't need to check if this repository supports tags,
491-
// because we know it :-)
492-
if (RuntimeEnvironment.getInstance().isTagsEnabled()) {
493-
assignTagsInHistory(history);
494-
}
495-
496-
return history;
497-
}
498-
499478
public void traverseHistory(File file, String sinceRevision, String tillRevision,
500479
Integer numCommits, List<ChangesetVisitor> visitors) throws HistoryException {
501480

opengrok-indexer/src/main/java/org/opengrok/indexer/history/HistoryCollector.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,17 @@ class HistoryCollector extends ChangesetVisitor {
3939

4040
public void accept(RepositoryWithHistoryTraversal.ChangesetInfo changesetInfo) {
4141
RepositoryWithHistoryTraversal.CommitInfo commit = changesetInfo.commit;
42+
43+
// TODO: add a test for this
44+
String author;
45+
if (commit.authorEmail != null) {
46+
author = commit.authorName + " <" + commit.authorEmail + ">";
47+
} else {
48+
author = commit.authorName;
49+
}
50+
4251
HistoryEntry historyEntry = new HistoryEntry(commit.revision,
43-
commit.date, commit.authorName + " <" + commit.authorEmail + ">",
52+
commit.date, author,
4453
commit.message, true);
4554

4655
if (changesetInfo.renamedFiles != null) {

opengrok-indexer/src/main/java/org/opengrok/indexer/history/MercurialHistoryParser.java

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
/*
21-
* Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
21+
* Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
2222
* Portions Copyright (c) 2017, Chris Fraire <[email protected]>.
2323
*/
2424
package org.opengrok.indexer.history;
@@ -33,10 +33,8 @@
3333
import java.text.ParseException;
3434
import java.util.ArrayList;
3535
import java.util.Date;
36-
import java.util.HashSet;
3736
import java.util.Iterator;
3837
import java.util.List;
39-
import java.util.Set;
4038
import java.util.logging.Level;
4139
import java.util.logging.Logger;
4240
import org.opengrok.indexer.configuration.RuntimeEnvironment;
@@ -54,67 +52,94 @@ class MercurialHistoryParser implements Executor.StreamHandler {
5452
/** Prefix which identifies lines with the description of a commit. */
5553
private static final String DESC_PREFIX = "description: ";
5654

57-
private List<HistoryEntry> entries = new ArrayList<>();
55+
private List<RepositoryWithHistoryTraversal.ChangesetInfo> entries = new ArrayList<>();
5856
private final MercurialRepository repository;
5957
private final String mydir;
6058
private boolean isDir;
61-
private final Set<String> renamedFiles = new HashSet<>();
59+
private final List<ChangesetVisitor> visitors;
6260

63-
MercurialHistoryParser(MercurialRepository repository) {
61+
MercurialHistoryParser(MercurialRepository repository, List<ChangesetVisitor> visitors) {
6462
this.repository = repository;
63+
this.visitors = visitors;
6564
mydir = repository.getDirectoryName() + File.separator;
6665
}
6766

6867
/**
6968
* Parse the history for the specified file or directory. If a changeset is
70-
* specified, only return the history from the changeset right after the
71-
* specified one.
69+
* specified, only return the history from the changeset right after the specified one.
7270
*
7371
* @param file the file or directory to get history for
7472
* @param sinceRevision the changeset right before the first one to fetch, or
7573
* {@code null} if all changesets should be fetched
7674
* @param tillRevision end revision or {@code null}
7775
* @param numCommits number of revisions to get
78-
* @return history for the specified file or directory
7976
* @throws HistoryException if an error happens when parsing the history
8077
*/
81-
History parse(File file, String sinceRevision, String tillRevision, Integer numCommits) throws HistoryException {
78+
void parse(File file, String sinceRevision, String tillRevision, Integer numCommits) throws HistoryException {
8279
isDir = file.isDirectory();
8380
try {
8481
Executor executor = repository.getHistoryLogExecutor(file, sinceRevision, tillRevision, false,
8582
numCommits);
8683
int status = executor.exec(true, this);
8784

8885
if (status != 0) {
89-
throw new HistoryException("Failed to get history for: \"" +
90-
file.getAbsolutePath() +
86+
throw new HistoryException("Failed to get history for: \"" + file.getAbsolutePath() +
9187
"\" Exit code: " + status);
9288
}
9389
} catch (IOException e) {
94-
throw new HistoryException("Failed to get history for: \"" +
95-
file.getAbsolutePath() + "\"", e);
90+
throw new HistoryException("Failed to get history for: \"" + file.getAbsolutePath() + "\"", e);
9691
}
9792

98-
// If a changeset to start from is specified, remove that changeset
99-
// from the list, since only the ones following it should be returned.
100-
// Also check that the specified changeset was found, otherwise throw
101-
// an exception.
93+
// If a changeset to start from is specified, remove that changeset from the list,
94+
// since only the ones following it should be returned.
95+
// Also check that the specified changeset was found, otherwise throw an exception.
10296
if (sinceRevision != null) {
103-
repository.removeAndVerifyOldestChangeset(entries, sinceRevision);
97+
removeAndVerifyOldestChangeset(entries, sinceRevision);
10498
}
10599

106100
// See getHistoryLogExecutor() for explanation.
107101
if (repository.isHandleRenamedFiles() && file.isFile() && tillRevision != null) {
108102
removeChangesets(entries, tillRevision);
109103
}
110104

111-
return new History(entries, renamedFiles);
105+
// The visitors are fed with the ChangesetInfo instances here (as opposed to in parse()),
106+
// because of the above manipulations with the entries.
107+
for (RepositoryWithHistoryTraversal.ChangesetInfo info : entries) {
108+
for (ChangesetVisitor visitor : visitors) {
109+
visitor.accept(info);
110+
}
111+
}
112+
}
113+
114+
/**
115+
* Remove the oldest changeset from a list (assuming sorted with most recent
116+
* changeset first) and verify that it is the changeset expected to find there.
117+
*
118+
* @param entries a list of {@code HistoryEntry} objects
119+
* @param revision the revision we expect the oldest entry to have
120+
* @throws HistoryException if the oldest entry was not the one we expected
121+
*/
122+
private void removeAndVerifyOldestChangeset(List<RepositoryWithHistoryTraversal.ChangesetInfo> entries, String revision)
123+
throws HistoryException {
124+
125+
RepositoryWithHistoryTraversal.ChangesetInfo entry = entries.isEmpty() ? null : entries.remove(entries.size() - 1);
126+
127+
// TODO We should check more thoroughly that the changeset is the one
128+
// we expected it to be, since some SCMs may change the revision
129+
// numbers so that identical revision numbers does not always mean
130+
// identical changesets. We could for example get the cached changeset
131+
// and compare more fields, like author and date.
132+
if (entry == null || !revision.equals(entry.commit.revision)) {
133+
throw new HistoryException("Cached revision '" + revision
134+
+ "' not found in the repository "
135+
+ repository.getDirectoryName());
136+
}
112137
}
113138

114-
private void removeChangesets(List<HistoryEntry> entries, String tillRevision) {
115-
for (Iterator<HistoryEntry> iter = entries.listIterator(); iter.hasNext(); ) {
116-
HistoryEntry entry = iter.next();
117-
if (entry.getRevision().equals(tillRevision)) {
139+
private void removeChangesets(List<RepositoryWithHistoryTraversal.ChangesetInfo> entries, String tillRevision) {
140+
for (Iterator<RepositoryWithHistoryTraversal.ChangesetInfo> iter = entries.listIterator(); iter.hasNext(); ) {
141+
RepositoryWithHistoryTraversal.ChangesetInfo entry = iter.next();
142+
if (entry.commit.revision.equals(tillRevision)) {
118143
break;
119144
}
120145
iter.remove();
@@ -123,7 +148,7 @@ private void removeChangesets(List<HistoryEntry> entries, String tillRevision) {
123148

124149
/**
125150
* Process the output from the {@code hg log} command and collect
126-
* {@link HistoryEntry} elements.
151+
* {@link org.opengrok.indexer.history.RepositoryWithHistoryTraversal.ChangesetInfo} elements.
127152
*
128153
* @param input The output from the process
129154
* @throws java.io.IOException If an error occurs while reading the stream
@@ -134,15 +159,14 @@ public void processStream(InputStream input) throws IOException {
134159
BufferedReader in = new BufferedReader(new InputStreamReader(input));
135160
entries = new ArrayList<>();
136161
String s;
137-
HistoryEntry entry = null;
162+
RepositoryWithHistoryTraversal.ChangesetInfo entry = null;
138163
while ((s = in.readLine()) != null) {
139164
if (s.startsWith(MercurialRepository.CHANGESET)) {
140-
entry = new HistoryEntry();
165+
entry = new RepositoryWithHistoryTraversal.ChangesetInfo(new RepositoryWithHistoryTraversal.CommitInfo());
141166
entries.add(entry);
142-
entry.setActive(true);
143-
entry.setRevision(s.substring(MercurialRepository.CHANGESET.length()).trim());
167+
entry.commit.revision = s.substring(MercurialRepository.CHANGESET.length()).trim();
144168
} else if (s.startsWith(MercurialRepository.USER) && entry != null) {
145-
entry.setAuthor(s.substring(MercurialRepository.USER.length()).trim());
169+
entry.commit.authorName = s.substring(MercurialRepository.USER.length()).trim();
146170
} else if (s.startsWith(MercurialRepository.DATE) && entry != null) {
147171
Date date;
148172
try {
@@ -154,15 +178,15 @@ public void processStream(InputStream input) throws IOException {
154178
//
155179
throw new IOException("Could not parse date: " + s, pe);
156180
}
157-
entry.setDate(date);
181+
entry.commit.date = date;
158182
} else if (s.startsWith(MercurialRepository.FILES) && entry != null) {
159183
String[] strings = s.split(" ");
160184
for (int ii = 1; ii < strings.length; ++ii) {
161185
if (strings[ii].length() > 0) {
162186
File f = new File(mydir, strings[ii]);
163187
try {
164188
String path = env.getPathRelativeToSourceRoot(f);
165-
entry.addFile(path.intern());
189+
entry.files.add(path.intern());
166190
} catch (ForbiddenSymlinkException e) {
167191
LOGGER.log(Level.FINER, e.getMessage());
168192
// ignore
@@ -189,11 +213,11 @@ public void processStream(InputStream input) throws IOException {
189213
String[] move = part.split(" \\(");
190214
File f = new File(mydir + move[0]);
191215
if (!move[0].isEmpty() && f.exists()) {
192-
renamedFiles.add(repository.getDirectoryNameRelative() + File.separator + move[0]);
216+
entry.renamedFiles.add(repository.getDirectoryNameRelative() + File.separator + move[0]);
193217
}
194218
}
195219
} else if (s.startsWith(DESC_PREFIX) && entry != null) {
196-
entry.setMessage(decodeDescription(s));
220+
entry.commit.message = decodeDescription(s);
197221
} else if (s.equals(MercurialRepository.END_OF_ENTRY)
198222
&& entry != null) {
199223
entry = null;

opengrok-indexer/src/main/java/org/opengrok/indexer/history/MercurialRepository.java

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
/*
21-
* Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
21+
* Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
2222
* Portions Copyright (c) 2017, 2019, Chris Fraire <[email protected]>.
2323
*/
2424
package org.opengrok.indexer.history;
@@ -52,7 +52,7 @@
5252
* Access to a Mercurial repository.
5353
*
5454
*/
55-
public class MercurialRepository extends RepositoryWithPerPartesHistory {
55+
public class MercurialRepository extends RepositoryWithHistoryTraversal {
5656

5757
private static final Logger LOGGER = LoggerFactory.getLogger(MercurialRepository.class);
5858

@@ -584,31 +584,12 @@ History getHistory(File file, String sinceRevision, String tillRevision) throws
584584
return getHistory(file, sinceRevision, tillRevision, null);
585585
}
586586

587-
History getHistory(File file, String sinceRevision, String tillRevision,
588-
Integer numCommits) throws HistoryException {
587+
// TODO: add a test for this
588+
public void traverseHistory(File file, String sinceRevision, String tillRevision,
589+
Integer numCommits, List<ChangesetVisitor> visitors) throws HistoryException {
589590

590-
if (numCommits != null && numCommits <= 0) {
591-
return null;
592-
}
593-
594-
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
595-
// Note that the filtering of revisions based on sinceRevision is done
596-
// in the history log executor by passing appropriate options to
597-
// the 'hg' executable.
598-
// This is done only for directories since if getHistory() is used
599-
// for file, the file is renamed and its complete history is fetched
600-
// so no sinceRevision filter is needed.
601-
// See findOriginalName() code for more details.
602-
History result = new MercurialHistoryParser(this).
591+
new MercurialHistoryParser(this, visitors).
603592
parse(file, sinceRevision, tillRevision, numCommits);
604-
605-
// Assign tags to changesets they represent.
606-
// We don't need to check if this repository supports tags,
607-
// because we know it :-)
608-
if (env.isTagsEnabled()) {
609-
assignTagsInHistory(result);
610-
}
611-
return result;
612593
}
613594

614595
/**

opengrok-indexer/src/main/java/org/opengrok/indexer/history/Repository.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,9 @@ public InputStream getHistoryGet(String parent, String basename, String rev) {
301301

302302
/**
303303
* Returns if this repository tags only files changed in last commit, i.e.
304-
* if we need to prepare list of repository-wide tags prior to creation of
305-
* file history entries.
304+
* if we need to prepare list of repository-wide tags prior to creation of file history entries.
306305
*
307-
* @return True if we need tag list creation prior to file parsing, false by
308-
* default.
306+
* @return True if we need tag list creation prior to file parsing, false by default.
309307
*/
310308
boolean hasFileBasedTags() {
311309
return false;

opengrok-indexer/src/main/java/org/opengrok/indexer/history/RepositoryWithHistoryTraversal.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
import java.io.File;
3232
import java.util.ArrayList;
3333
import java.util.Date;
34+
import java.util.HashSet;
3435
import java.util.List;
3536
import java.util.Set;
3637
import java.util.SortedSet;
38+
import java.util.TreeSet;
3739
import java.util.logging.Level;
3840
import java.util.logging.Logger;
3941

@@ -50,6 +52,9 @@ public static class CommitInfo {
5052
String authorEmail;
5153
String message;
5254

55+
CommitInfo() {
56+
}
57+
5358
CommitInfo(String revision, Date date, String authorName, String authorEmail, String message) {
5459
this.revision = revision;
5560
this.date = date;
@@ -67,6 +72,9 @@ public static class ChangesetInfo {
6772

6873
ChangesetInfo(CommitInfo commit) {
6974
this.commit = commit;
75+
this.files = new TreeSet<>();
76+
this.renamedFiles = new HashSet<>();
77+
this.deletedFiles = new HashSet<>();
7078
}
7179

7280
ChangesetInfo(CommitInfo commit, SortedSet<String> files, Set<String> renamedFiles, Set<String> deletedFiles) {
@@ -89,6 +97,25 @@ public static class ChangesetInfo {
8997
public abstract void traverseHistory(File file, String sinceRevision, @Nullable String tillRevision,
9098
Integer numCommits, List<ChangesetVisitor> visitors) throws HistoryException;
9199

100+
public History getHistory(File file, String sinceRevision, String tillRevision,
101+
Integer numCommits) throws HistoryException {
102+
103+
if (numCommits != null && numCommits <= 0) {
104+
return null;
105+
}
106+
107+
HistoryCollector historyCollector = new HistoryCollector(isMergeCommitsEnabled());
108+
traverseHistory(file, sinceRevision, tillRevision, numCommits, List.of(historyCollector));
109+
History history = new History(historyCollector.entries, historyCollector.renamedFiles);
110+
111+
// Assign tags to changesets they represent.
112+
if (RuntimeEnvironment.getInstance().isTagsEnabled() && hasFileBasedTags()) {
113+
assignTagsInHistory(history);
114+
}
115+
116+
return history;
117+
}
118+
92119
@Override
93120
protected void doCreateCache(HistoryCache cache, String sinceRevision, File directory) throws HistoryException {
94121
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
@@ -115,8 +142,7 @@ protected void doCreateCache(HistoryCache cache, String sinceRevision, File dire
115142
History history = new History(historyCollector.entries, historyCollector.renamedFiles);
116143

117144
// Assign tags to changesets they represent.
118-
// We don't need to check if this repository supports tags, because we know it :-)
119-
if (env.isTagsEnabled()) {
145+
if (env.isTagsEnabled() && hasFileBasedTags()) {
120146
assignTagsInHistory(history);
121147
}
122148

@@ -150,8 +176,7 @@ protected void doCreateCache(HistoryCache cache, String sinceRevision, File dire
150176
History history = new History(historyCollector.entries, historyCollector.renamedFiles);
151177

152178
// Assign tags to changesets they represent.
153-
// We don't need to check if this repository supports tags, because we know it :-)
154-
if (env.isTagsEnabled()) {
179+
if (env.isTagsEnabled() && hasFileBasedTags()) {
155180
assignTagsInHistory(history);
156181
}
157182

0 commit comments

Comments
 (0)