Skip to content

Commit 796b45a

Browse files
authored
Fixes #761, #3093 (svn history on renamed files, svn date parsing) (#3095)
1 parent 1d477ae commit 796b45a

File tree

8 files changed

+585
-48
lines changed

8 files changed

+585
-48
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@
1212
*.PDF diff=astextplain
1313
*.rtf diff=astextplain
1414
*.RTF diff=astextplain
15+
16+
/testdata/svndump/svnlog.dump text eol=lf

opengrok-indexer/build.xml

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
3030

3131
<property name="test.repositories" value="../testdata/repositories"/>
3232
<property name="test.sources" value="../testdata/sources"/>
33+
<property name="test.svndump" value="../testdata/svndump"/>
3334
<property name="test.plugins" value="../testdata/plugins"/>
3435
<property name="test.cvs" value="${test.repositories}/cvs_test"/>
3536
<property name="test.cvs.repo" value="${test.cvs}/cvsrepo"/>
@@ -39,6 +40,7 @@ Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
3940
<property name="test.hg" value="${test.repositories}/mercurial"/>
4041
<property name="test.git" value="${test.repositories}/git"/>
4142
<property name="test.svn" value="${test.repositories}/svn"/>
43+
<property name="test.svn2" value="${test.repositories}/subversion"/>
4244
<property name="test.razor" value="${test.repositories}/razor"/>
4345
<property name="test.razor.repo" value="../ext/SampleRazorRepository/"/>
4446
<property name="build.test.reposroots" value="target/reposroot"/>
@@ -122,6 +124,10 @@ Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
122124
<map from="" to="file:///"/>
123125
<path location="${build.test.reposroots}/svn"/>
124126
</pathconvert>
127+
<pathconvert property="test.svn.url2">
128+
<map from="" to="file:///"/>
129+
<path location="${build.test.reposroots}/svn2"/>
130+
</pathconvert>
125131

126132
<exec executable="svn" failifexecutionfails="false">
127133
<arg value="import"/>
@@ -135,6 +141,22 @@ Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
135141
<arg value="${test.svn.url}"/>
136142
<arg value="${test.svn}"/>
137143
</exec>
144+
145+
<exec executable="svnadmin" failifexecutionfails="true">
146+
<arg value="create"/>
147+
<arg value="${build.test.reposroots}/svn2"/>
148+
</exec>
149+
150+
<exec executable="svnadmin" input="${test.svndump}/svnlog.dump" failifexecutionfails="true">
151+
<arg value="load"/>
152+
<arg value="${build.test.reposroots}/svn2"/>
153+
</exec>
154+
155+
<exec executable="svn" failifexecutionfails="false">
156+
<arg value="checkout"/>
157+
<arg value="${test.svn.url2}"/>
158+
<arg value="${test.svn2}"/>
159+
</exec>
138160
</target>
139161

140162
<target name="-create-razor-repository">
@@ -158,13 +180,14 @@ Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
158180
</target>
159181

160182
<!-- clean up generated test repositories -->
161-
<target name="-delete-generated-repository-files">
183+
<target name="-delete-generated-repository-files">
162184
<delete dir="${test.bk}/.bk"/>
163185
<delete dir="${test.bzr}/.bzr"/>
164186
<delete dir="${test.hg}/.hg"/>
165187
<delete file="${test.hg}/.hgignore"/>
166188
<delete dir="${test.git}/.git"/>
167189
<delete dir="${test.svn}"/>
190+
<delete dir="${test.svn2}"/>
168191
<delete dir="${test.razor}"/>
169192
<delete file="${test.cvs.repo}/CVS/Root"/>
170193
</target>

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
/*
2121
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
2222
* Portions Copyright (c) 2017, Chris Fraire <cfraire@me.com>.
23+
* Portions Copyright (c) 2020, Ric Harris <harrisric@users.noreply.github.com>.
2324
*/
2425
package org.opengrok.indexer.history;
2526

@@ -30,11 +31,15 @@
3031
import java.io.InputStream;
3132
import java.text.ParseException;
3233
import java.util.ArrayList;
34+
import java.util.HashSet;
3335
import java.util.List;
36+
import java.util.Set;
3437
import java.util.logging.Level;
3538
import java.util.logging.Logger;
39+
3640
import javax.xml.parsers.SAXParser;
3741
import javax.xml.parsers.SAXParserFactory;
42+
3843
import org.opengrok.indexer.configuration.RuntimeEnvironment;
3944
import org.opengrok.indexer.logger.LoggerFactory;
4045
import org.opengrok.indexer.util.Executor;
@@ -56,13 +61,20 @@ class SubversionHistoryParser implements Executor.StreamHandler {
5661

5762
private static class Handler extends DefaultHandler2 {
5863

64+
/**
65+
* Example of the longest date format that we should accept - SimpleDateFormat cannot cope with micro/nano seconds.
66+
*/
67+
static final int SVN_MILLIS_DATE_LENGTH = "2020-03-26T15:38:55.999Z".length();
68+
5969
final String prefix;
6070
final String home;
6171
final int length;
62-
final List<HistoryEntry> entries = new ArrayList<HistoryEntry>();
72+
final List<HistoryEntry> entries = new ArrayList<>();
73+
final Set<String> renamedFiles = new HashSet<>();
6374
final SubversionRepository repository;
6475
HistoryEntry entry;
6576
StringBuilder sb;
77+
boolean isRenamed;
6678

6779
Handler(String home, String prefix, int length, SubversionRepository repository) {
6880
this.home = home;
@@ -72,12 +84,19 @@ private static class Handler extends DefaultHandler2 {
7284
sb = new StringBuilder();
7385
}
7486

87+
List<String> getRenamedFiles() {
88+
return new ArrayList<>(renamedFiles);
89+
}
90+
7591
@Override
7692
public void startElement(String uri, String localName, String qname, Attributes attr) {
93+
isRenamed = false;
7794
if ("logentry".equals(qname)) {
7895
entry = new HistoryEntry();
7996
entry.setActive(true);
8097
entry.setRevision(attr.getValue("revision"));
98+
} else if ("path".equals(qname)) {
99+
isRenamed = attr.getIndex("copyfrom-path") != -1;
81100
}
82101
sb.setLength(0);
83102
}
@@ -89,7 +108,13 @@ public void endElement(String uri, String localName, String qname) throws SAXExc
89108
entry.setAuthor(s);
90109
} else if ("date".equals(qname)) {
91110
try {
92-
entry.setDate(repository.parse(s));
111+
// need to strip microseconds off - assume final character is Z otherwise invalid anyway.
112+
String dateString = s;
113+
if (s.length() > SVN_MILLIS_DATE_LENGTH) {
114+
dateString = dateString.substring(0, SVN_MILLIS_DATE_LENGTH - 1) +
115+
dateString.charAt(dateString.length() - 1);
116+
}
117+
entry.setDate(repository.parse(dateString));
93118
} catch (ParseException ex) {
94119
throw new SAXException("Failed to parse date: " + s, ex);
95120
}
@@ -104,6 +129,9 @@ public void endElement(String uri, String localName, String qname) throws SAXExc
104129
// The same file names may be repeated in many commits,
105130
// so intern them to reduce the memory footprint.
106131
entry.addFile(path.intern());
132+
if (isRenamed) {
133+
renamedFiles.add(file.getAbsolutePath().substring(home.length() + 1));
134+
}
107135
} else {
108136
LOGGER.log(Level.FINER, "Skipping file outside repository: " + s);
109137
}
@@ -177,7 +205,7 @@ History parse(File file, SubversionRepository repos, String sinceRevision,
177205
repos.removeAndVerifyOldestChangeset(entries, sinceRevision);
178206
}
179207

180-
return new History(entries);
208+
return new History(entries, handler.getRenamedFiles());
181209
}
182210

183211
/**
@@ -206,6 +234,6 @@ public void processStream(InputStream input) throws IOException {
206234
History parse(String buffer) throws IOException {
207235
handler = new Handler("/", "", 0, new SubversionRepository());
208236
processStream(new ByteArrayInputStream(buffer.getBytes("UTF-8")));
209-
return new History(handler.entries);
237+
return new History(handler.entries, handler.getRenamedFiles());
210238
}
211239
}

0 commit comments

Comments
 (0)