Skip to content

Commit de1d285

Browse files
authored
Merge pull request #1630 from vladak/cvs_determineBranch
various CVS fixes
2 parents 352dbc8 + 71a0e9c commit de1d285

File tree

5 files changed

+177
-40
lines changed

5 files changed

+177
-40
lines changed

build.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
787787

788788
<!-- Change root in CVS test repository -->
789789
<!-- Strange indentation in line two levels below to get newline correctly -->
790+
<!-- This will be changed again in the CVS tests -->
790791
<concat destfile="${test.cvs.repo}/CVS/Root" append="no" force="yes" eol="unix">${basedir}/${test.cvs.root}/
791792
</concat>
792793

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
import java.text.DateFormat;
3232
import java.text.ParseException;
3333
import java.util.ArrayList;
34+
import java.util.Collections;
35+
import java.util.Comparator;
3436
import java.util.HashMap;
37+
import java.util.List;
3538
import java.util.logging.Level;
3639
import java.util.logging.Logger;
3740

@@ -50,7 +53,7 @@ private enum ParseState {
5053
}
5154

5255
private History history;
53-
private CVSRepository repository = new CVSRepository();
56+
private CVSRepository cvsrepo = new CVSRepository();
5457

5558
/**
5659
* Process the output from the log command and insert the HistoryEntries
@@ -61,7 +64,7 @@ private enum ParseState {
6164
*/
6265
@Override
6366
public void processStream(InputStream input) throws IOException {
64-
DateFormat df = repository.getDateFormat();
67+
DateFormat df = cvsrepo.getDateFormat();
6568
ArrayList<HistoryEntry> entries = new ArrayList<HistoryEntry>();
6669

6770
BufferedReader in = new BufferedReader(new InputStreamReader(input));
@@ -169,9 +172,9 @@ public void processStream(InputStream input) throws IOException {
169172
* @return object representing the file's history
170173
*/
171174
History parse(File file, Repository repos) throws HistoryException {
172-
repository = (CVSRepository) repos;
175+
cvsrepo = (CVSRepository) repos;
173176
try {
174-
Executor executor = repository.getHistoryLogExecutor(file);
177+
Executor executor = cvsrepo.getHistoryLogExecutor(file);
175178
int status = executor.exec(true, this);
176179

177180
if (status != 0) {
@@ -183,6 +186,19 @@ History parse(File file, Repository repos) throws HistoryException {
183186
file.getAbsolutePath() + "\"", e);
184187
}
185188

189+
// In case there is a branch, the log entries can be returned in
190+
// unsorted order (as a result of using '-r1.1:branch' for 'cvs log')
191+
// so they need to be sorted according to revision.
192+
if (cvsrepo.getBranch() != null && !cvsrepo.getBranch().isEmpty()) {
193+
List<HistoryEntry> entries = history.getHistoryEntries();
194+
Collections.sort(entries, new Comparator<HistoryEntry>() {
195+
public int compare(HistoryEntry o1, HistoryEntry o2) {
196+
return o2.getRevision().compareTo(o1.getRevision());
197+
}
198+
});
199+
history.setHistoryEntries(entries);
200+
}
201+
186202
return history;
187203
}
188204

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

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,8 @@ public class CVSRepository extends RCSRepository {
5757
*/
5858
public static final String CMD_FALLBACK = "cvs";
5959

60-
private Boolean isBranch = null;
61-
private String branch = null;
62-
6360
/**
64-
* Pattern used to extract author/revision from cvs annotate.
61+
* Pattern used to extract author/revision from 'cvs annotate'.
6562
*/
6663
private static final Pattern ANNOTATE_PATTERN
6764
= Pattern.compile("([\\.\\d]+)\\W+\\((\\w+)");
@@ -165,6 +162,31 @@ public void update() throws IOException {
165162
}
166163
}
167164

165+
@Override
166+
String determineBranch() throws IOException {
167+
String branch = null;
168+
169+
File tagFile = new File(getDirectoryName(), "CVS/Tag");
170+
if (tagFile.isFile()) {
171+
try (BufferedReader br = new BufferedReader(new FileReader(tagFile))) {
172+
String line = br.readLine();
173+
if (line != null) {
174+
branch = line.substring(1);
175+
}
176+
} catch (IOException ex) {
177+
LOGGER.log(Level.WARNING,
178+
"Failed to work with CVS/Tag file of {0}",
179+
getDirectoryName() + ": " + ex.getClass().toString());
180+
} catch (Exception exp) {
181+
LOGGER.log(Level.WARNING,
182+
"Failed to get revision tag of {0}",
183+
getDirectoryName() + ": " + exp.getClass().toString());
184+
}
185+
}
186+
187+
return branch;
188+
}
189+
168190
/**
169191
* Get an executor to be used for retrieving the history log for the named
170192
* file.
@@ -184,33 +206,9 @@ Executor getHistoryLogExecutor(final File file) throws IOException {
184206
cmd.add(RepoCommand);
185207
cmd.add("log");
186208

187-
if (isBranch == null) {
188-
File tagFile = new File(getDirectoryName(), "CVS/Tag");
189-
if (tagFile.isFile()) {
190-
isBranch = Boolean.TRUE;
191-
try (BufferedReader br = new BufferedReader(new FileReader(tagFile))) {
192-
String line = br.readLine();
193-
if (line != null) {
194-
branch = line.substring(1);
195-
}
196-
} catch (IOException ex) {
197-
LOGGER.log(Level.WARNING,
198-
"Failed to work with CVS/Tag file of {0}",
199-
getDirectoryName() + ": " + ex.getClass().toString());
200-
} catch (Exception exp) {
201-
LOGGER.log(Level.WARNING,
202-
"Failed to get revision tag of {0}",
203-
getDirectoryName() + ": " + exp.getClass().toString());
204-
}
205-
} else {
206-
isBranch = Boolean.FALSE;
207-
}
208-
}
209-
210-
if (isBranch.equals(Boolean.TRUE) && branch != null && !branch.isEmpty()) {
211-
// Just generate THIS branch history, we don't care about the other
212-
// branches which are not checked out.
213-
cmd.add("-r" + branch);
209+
if (getBranch() != null && !getBranch().isEmpty()) {
210+
// Generate history on this branch and follow up to the origin.
211+
cmd.add("-r1.1:" + branch);
214212
} else {
215213
// Get revisions on this branch only (otherwise the revisions
216214
// list produced by the cvs log command would be unsorted).
@@ -220,6 +218,7 @@ Executor getHistoryLogExecutor(final File file) throws IOException {
220218
if (filename.length() > 0) {
221219
cmd.add(filename);
222220
}
221+
223222
return new Executor(cmd, new File(getDirectoryName()));
224223
}
225224

@@ -296,6 +295,9 @@ Annotation annotate(File file, String revision) throws IOException {
296295
if (revision != null) {
297296
cmd.add("-r");
298297
cmd.add(revision);
298+
} else if (getBranch() != null && !getBranch().isEmpty()) {
299+
cmd.add("-r");
300+
cmd.add(getBranch());
299301
}
300302
cmd.add(file.getName());
301303

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ String determineParent() throws IOException {
180180
}
181181

182182
@Override
183-
String determineBranch() {
183+
String determineBranch() throws IOException {
184184
return null;
185185
}
186186
}

test/org/opensolaris/opengrok/history/CVSRepositoryTest.java

Lines changed: 122 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,19 @@
1818
*/
1919

2020
/*
21-
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
21+
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
2222
*/
2323
package org.opensolaris.opengrok.history;
2424

25+
import java.io.File;
26+
import java.io.FileOutputStream;
27+
import java.io.FileWriter;
28+
import java.io.IOException;
2529
import java.io.Reader;
2630
import java.io.StringReader;
31+
import java.nio.channels.FileChannel;
32+
import java.util.ArrayList;
33+
import java.util.List;
2734
import org.junit.After;
2835
import org.junit.AfterClass;
2936
import org.junit.Before;
@@ -35,6 +42,9 @@
3542
import org.opensolaris.opengrok.condition.RepositoryInstalled;
3643

3744
import static org.junit.Assert.*;
45+
import org.opensolaris.opengrok.util.Executor;
46+
import org.opensolaris.opengrok.util.IOUtils;
47+
import org.opensolaris.opengrok.util.TestRepository;
3848

3949
/**
4050
*
@@ -59,14 +69,122 @@ public static void setUpClass() throws Exception {
5969
public static void tearDownClass() throws Exception {
6070
}
6171

62-
@Before
63-
public void setUp() {
64-
instance = new CVSRepository();
72+
private TestRepository repository;
73+
74+
/**
75+
* Set up a test repository. Should be called by the tests that need it. The
76+
* test repository will be destroyed automatically when the test finishes.
77+
*/
78+
private void setUpTestRepository() throws IOException {
79+
repository = new TestRepository();
80+
repository.create(getClass().getResourceAsStream("repositories.zip"));
81+
82+
// Checkout cvsrepo anew in order to get the CVS/Root files point to
83+
// the temporary directory rather than the OpenGrok workspace directory
84+
// it was created from. This is necessary since 'cvs update' changes
85+
// the CVS parent directory after branch has been created.
86+
File root = new File(repository.getSourceRoot(), "cvs_test");
87+
File cvsrepodir = new File(root, "cvsrepo");
88+
IOUtils.removeRecursive(cvsrepodir.toPath());
89+
File cvsroot = new File(root, "cvsroot");
90+
runCvsCommand(root, "-d", cvsroot.getAbsolutePath(), "checkout", "cvsrepo");
6591
}
6692

6793
@After
6894
public void tearDown() {
6995
instance = null;
96+
97+
if (repository != null) {
98+
repository.destroy();
99+
repository = null;
100+
}
101+
}
102+
103+
@Before
104+
public void setUp() {
105+
instance = new CVSRepository();
106+
}
107+
108+
/**
109+
* Run the 'cvs' command with some arguments.
110+
*
111+
* @param reposRoot directory of the repository root
112+
* @param args arguments to use for the command
113+
*/
114+
private static void runCvsCommand(File reposRoot, String ... args) {
115+
List<String> cmdargs = new ArrayList<>();
116+
cmdargs.add(CVSRepository.CMD_FALLBACK);
117+
for (String arg: args) {
118+
cmdargs.add(arg);
119+
}
120+
Executor exec = new Executor(cmdargs, reposRoot);
121+
int exitCode = exec.exec();
122+
if (exitCode != 0) {
123+
fail("cvs command '" + cmdargs.toString() + "'failed."
124+
+ "\nexit code: " + exitCode
125+
+ "\nstdout:\n" + exec.getOutputString()
126+
+ "\nstderr:\n" + exec.getErrorString());
127+
}
128+
}
129+
130+
/**
131+
* Get the CVS repository, test that getBranch() returns null if there is
132+
* no branch.
133+
* @throws Exception
134+
*/
135+
@Test
136+
public void testGetBranchNoBranch() throws Exception {
137+
setUpTestRepository();
138+
File root = new File(repository.getSourceRoot(), "cvs_test/cvsrepo");
139+
CVSRepository cvsrepo
140+
= (CVSRepository) RepositoryFactory.getRepository(root);
141+
assertEquals(null, cvsrepo.getBranch());
142+
}
143+
144+
/**
145+
* Get the CVS repository, create new branch, change a file and verify that
146+
* getBranch() returns the branch and check newly added commits annotate
147+
* with branch revision numbers.
148+
* Last, check that history entries of the file follow through before the
149+
* branch was created.
150+
* @throws Exception
151+
*/
152+
@Test
153+
public void testNewBranch() throws Exception {
154+
setUpTestRepository();
155+
File root = new File(repository.getSourceRoot(), "cvs_test/cvsrepo");
156+
157+
// Create new branch and switch to it.
158+
runCvsCommand(root, "tag", "-b", "mybranch");
159+
// Note that the 'update' command will change the entries in 'cvsroot' directory.
160+
runCvsCommand(root, "update", "-r", "mybranch");
161+
162+
// Now the repository object can be instantiated so that determineBranch()
163+
// will be called.
164+
CVSRepository cvsrepo
165+
= (CVSRepository) RepositoryFactory.getRepository(root);
166+
167+
assertEquals("mybranch", cvsrepo.getBranch());
168+
169+
// Change the content and commit.
170+
File mainC = new File(root, "main.c");
171+
FileChannel outChan = new FileOutputStream(mainC, true).getChannel();
172+
outChan.truncate(0);
173+
outChan.close();
174+
FileWriter fw = new FileWriter(mainC);
175+
fw.write("#include <foo.h>\n");
176+
fw.close();
177+
runCvsCommand(root, "commit", "-m", "change on a branch", "main.c");
178+
179+
// Check that annotation for the changed line has branch revision.
180+
Annotation annotation = cvsrepo.annotate(mainC, null);
181+
assertEquals("1.2.2.1", annotation.getRevision(1));
182+
183+
History mainCHistory = cvsrepo.getHistory(mainC);
184+
assertEquals(3, mainCHistory.getHistoryEntries().size());
185+
assertEquals("1.2.2.1", mainCHistory.getHistoryEntries().get(0).getRevision());
186+
assertEquals("1.2", mainCHistory.getHistoryEntries().get(1).getRevision());
187+
assertEquals("1.1", mainCHistory.getHistoryEntries().get(2).getRevision());
70188
}
71189

72190
/**

0 commit comments

Comments
 (0)