Skip to content

Commit cff3e28

Browse files
authored
Merge pull request #3154 from idodeclare/feature/more_nesting
Resolve #3010 : add --nestingMaximum switch
2 parents 52d5543 + 2402fe1 commit cff3e28

File tree

6 files changed

+96
-23
lines changed

6 files changed

+96
-23
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/Configuration.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
/*
2121
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
22-
* Portions Copyright (c) 2017-2019, Chris Fraire <[email protected]>.
22+
* Portions Copyright (c) 2017-2020, Chris Fraire <[email protected]>.
2323
* Portions Copyright (c) 2020, Aleksandr Kirillov <[email protected]>.
2424
*/
2525
package org.opengrok.indexer.configuration;
@@ -206,6 +206,7 @@ public final class Configuration {
206206
private boolean lastEditedDisplayMode;
207207
private String CTagsExtraOptionsFile;
208208
private int scanningDepth;
209+
private int nestingMaximum;
209210
private Set<String> allowedSymlinks;
210211
private Set<String> canonicalRoots;
211212
private boolean obfuscatingEMailAddresses;
@@ -356,6 +357,26 @@ public void setScanningDepth(int scanningDepth) throws IllegalArgumentException
356357
this.scanningDepth = scanningDepth;
357358
}
358359

360+
/**
361+
* Gets the nesting maximum of repositories. Default is 1.
362+
*/
363+
public int getNestingMaximum() {
364+
return nestingMaximum;
365+
}
366+
367+
/**
368+
* Sets the nesting maximum of repositories to a specified value.
369+
* @param nestingMaximum the new value
370+
* @throws IllegalArgumentException if {@code nestingMaximum} is negative
371+
*/
372+
public void setNestingMaximum(int nestingMaximum) throws IllegalArgumentException {
373+
if (nestingMaximum < 0) {
374+
throw new IllegalArgumentException(
375+
String.format(NEGATIVE_NUMBER_ERROR, "nestingMaximum", nestingMaximum));
376+
}
377+
this.nestingMaximum = nestingMaximum;
378+
}
379+
359380
public int getCommandTimeout() {
360381
return commandTimeout;
361382
}
@@ -487,6 +508,7 @@ public Configuration() {
487508
setMaxRevisionThreadCount(Runtime.getRuntime().availableProcessors());
488509
setMessageLimit(500);
489510
setNavigateWindowEnabled(false);
511+
setNestingMaximum(1);
490512
setOptimizeDatabase(true);
491513
setPluginDirectory(null);
492514
setPluginStack(new AuthorizationStack(AuthControlFlag.REQUIRED, "default stack"));

opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/RuntimeEnvironment.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,14 @@ public void setScanningDepth(int scanningDepth) {
214214
syncWriteConfiguration(scanningDepth, Configuration::setScanningDepth);
215215
}
216216

217+
public int getNestingMaximum() {
218+
return syncReadConfiguration(Configuration::getNestingMaximum);
219+
}
220+
221+
public void setNestingMaximum(int nestingMaximum) {
222+
syncWriteConfiguration(nestingMaximum, Configuration::setNestingMaximum);
223+
}
224+
217225
public int getCommandTimeout() {
218226
return syncReadConfiguration(Configuration::getCommandTimeout);
219227
}

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,13 @@ public final class HistoryGuru {
7878
/**
7979
* Map of repositories, with {@code DirectoryName} as key.
8080
*/
81-
private Map<String, Repository> repositories = new ConcurrentHashMap<>();
81+
private final Map<String, Repository> repositories = new ConcurrentHashMap<>();
8282

8383
/**
8484
* Set of repository roots (using ConcurrentHashMap but a throwaway value)
8585
* with parent of {@code DirectoryName} as key.
8686
*/
87-
private Map<String, String> repositoryRoots = new ConcurrentHashMap<>();
87+
private final Map<String, String> repositoryRoots = new ConcurrentHashMap<>();
8888

8989
private final int scanningDepth;
9090

@@ -388,15 +388,15 @@ public Map<String, Date> getLastModifiedTimes(File directory)
388388
*
389389
* @param files list of files to check if they contain a repository
390390
* @param ignoredNames what files to ignore
391-
* @param recursiveSearch whether to use recursive search
391+
* @param allowedNesting number of levels of nested repos to allow
392392
* @param depth current depth - using global scanningDepth - one can limit
393393
* this to improve scanning performance
394394
* @param isNested a value indicating if a parent {@link Repository} was
395395
* already found above the {@code files}
396396
* @return collection of added repositories
397397
*/
398398
private Collection<RepositoryInfo> addRepositories(File[] files,
399-
IgnoredNames ignoredNames, boolean recursiveSearch, int depth,
399+
IgnoredNames ignoredNames, int allowedNesting, int depth,
400400
boolean isNested) {
401401

402402
List<RepositoryInfo> repoList = new ArrayList<>();
@@ -436,7 +436,7 @@ private Collection<RepositoryInfo> addRepositories(File[] files,
436436
file.getAbsolutePath());
437437
} else if (depth <= scanningDepth) {
438438
repoList.addAll(addRepositories(subFiles, ignoredNames,
439-
recursiveSearch, depth + 1, isNested));
439+
allowedNesting, depth + 1, isNested));
440440
}
441441
}
442442
} else {
@@ -446,17 +446,17 @@ private Collection<RepositoryInfo> addRepositories(File[] files,
446446
repoList.add(new RepositoryInfo(repository));
447447
putRepository(repository);
448448

449-
if (recursiveSearch && repository.supportsSubRepositories()) {
449+
if (allowedNesting > 0 && repository.supportsSubRepositories()) {
450450
File[] subFiles = file.listFiles();
451451
if (subFiles == null) {
452452
LOGGER.log(Level.WARNING,
453453
"Failed to get sub directories for ''{0}'', check access permissions.",
454454
file.getAbsolutePath());
455455
} else if (depth <= scanningDepth) {
456-
// Search only one level down - if not: too much
456+
// Search down to a limit -- if not: too much
457457
// stat'ing for huge Mercurial repositories
458458
repoList.addAll(addRepositories(subFiles, ignoredNames,
459-
false, depth + 1, true));
459+
allowedNesting - 1, depth + 1, true));
460460
}
461461
}
462462
}
@@ -482,7 +482,7 @@ private Collection<RepositoryInfo> addRepositories(File[] files,
482482
public Collection<RepositoryInfo> addRepositories(File[] files,
483483
IgnoredNames ignoredNames) {
484484

485-
return addRepositories(files, ignoredNames, true, 0, false);
485+
return addRepositories(files, ignoredNames, env.getNestingMaximum(), 0, false);
486486
}
487487

488488
/**
@@ -633,19 +633,17 @@ public void createCache(Collection<String> repositories) {
633633
*
634634
* @param repositories list of repository paths relative to source root
635635
* @return list of repository paths that were found and their history data removed
636-
* @throws HistoryException if history cannot be retrieved
637636
*/
638-
public List<String> clearCache(Collection<String> repositories) throws HistoryException {
637+
public List<String> clearCache(Collection<String> repositories) {
639638
List<String> clearedRepos = new ArrayList<>();
640-
HistoryCache cache = historyCache;
641639

642640
if (!useCache()) {
643641
return clearedRepos;
644642
}
645643

646644
for (Repository r : getReposFromString(repositories)) {
647645
try {
648-
cache.clear(r);
646+
historyCache.clear(r);
649647
clearedRepos.add(r.getDirectoryName());
650648
LOGGER.log(Level.INFO,
651649
"History cache for {0} cleared.", r.getDirectoryName());
@@ -676,9 +674,8 @@ public void clearCacheFile(String path) {
676674
* successfully cleared are removed from the internal list of repositories.
677675
*
678676
* @param repositories list of repository paths relative to source root
679-
* @throws HistoryException if history cannot be retrieved
680677
*/
681-
public void removeCache(Collection<String> repositories) throws HistoryException {
678+
public void removeCache(Collection<String> repositories) {
682679
if (!useCache()) {
683680
return;
684681
}

opengrok-indexer/src/main/java/org/opengrok/indexer/index/Indexer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,10 @@ public static String[] parseOptions(String[] argv) throws ParseException {
599599
"files), but process all other command line options.").Do(v ->
600600
runIndex = false);
601601

602+
parser.on("--nestingMaximum", "=number",
603+
"Maximum of nested repositories. Default is 1.").Do(v ->
604+
cfg.setNestingMaximum((Integer) v));
605+
602606
parser.on("-O", "--optimize", "=on|off", ON_OFF, Boolean.class,
603607
"Turn on/off the optimization of the index database as part of the",
604608
"indexing step. Default is on.").

opengrok-indexer/src/test/java/org/opengrok/indexer/history/HistoryGuruTest.java

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
/*
2121
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
22-
* Portions Copyright (c) 2019, Chris Fraire <[email protected]>.
22+
* Portions Copyright (c) 2019-2020, Chris Fraire <[email protected]>.
2323
*/
2424
package org.opengrok.indexer.history;
2525

@@ -36,6 +36,7 @@
3636
import java.util.Collections;
3737
import java.util.List;
3838

39+
import org.junit.After;
3940
import org.junit.AfterClass;
4041
import org.junit.Assert;
4142
import org.junit.BeforeClass;
@@ -58,14 +59,18 @@ public class HistoryGuruTest {
5859

5960
private static TestRepository repository = new TestRepository();
6061
private static final List<File> FILES = new ArrayList<>();
62+
private static RuntimeEnvironment env;
63+
64+
private static int savedNestingMaximum;
6165

6266
@Rule
6367
public ConditionalRunRule rule = new ConditionalRunRule();
6468

6569
@BeforeClass
6670
public static void setUpClass() throws Exception {
67-
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
68-
71+
env = RuntimeEnvironment.getInstance();
72+
savedNestingMaximum = env.getNestingMaximum();
73+
6974
repository = new TestRepository();
7075
repository.create(HistoryGuru.class.getResourceAsStream(
7176
"repositories.zip"));
@@ -96,6 +101,11 @@ public static void tearDownClass() {
96101
repository.destroy();
97102
}
98103

104+
@After
105+
public void tearDown() {
106+
env.setNestingMaximum(savedNestingMaximum);
107+
}
108+
99109
@Test
100110
public void testGetRevision() throws HistoryException, IOException {
101111
HistoryGuru instance = HistoryGuru.getInstance();
@@ -147,7 +157,6 @@ public void getCacheInfo() throws HistoryException {
147157
@ConditionalRun(RepositoryInstalled.GitInstalled.class)
148158
public void testAddRemoveRepositories() {
149159
HistoryGuru instance = HistoryGuru.getInstance();
150-
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
151160
final int numReposOrig = instance.getRepositories().size();
152161

153162
// Try to add non-existent repository.
@@ -175,7 +184,6 @@ public void testAddRemoveRepositories() {
175184
@ConditionalRun(RepositoryInstalled.MercurialInstalled.class)
176185
public void testAddSubRepositoryNotNestable() {
177186
HistoryGuru instance = HistoryGuru.getInstance();
178-
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
179187

180188
// Check out CVS underneath a Git repository.
181189
File cvsRoot = new File(repository.getSourceRoot(), "cvs_test");
@@ -197,7 +205,6 @@ public void testAddSubRepositoryNotNestable() {
197205
@ConditionalRun(RepositoryInstalled.MercurialInstalled.class)
198206
public void testAddSubRepository() {
199207
HistoryGuru instance = HistoryGuru.getInstance();
200-
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
201208

202209
// Clone a Mercurial repository underneath a Mercurial repository.
203210
File hgRoot = new File(repository.getSourceRoot(), "mercurial");
@@ -211,4 +218,39 @@ public void testAddSubRepository() {
211218
env.getIgnoredNames());
212219
assertEquals(2, addedRepos.size());
213220
}
221+
222+
@Test
223+
public void testNestingMaximum() throws IOException {
224+
// Just fake a nesting of Repo -> Git -> Git.
225+
File repoRoot = new File(repository.getSourceRoot(), "repoRoot");
226+
certainlyMkdirs(repoRoot);
227+
File repo0 = new File(repoRoot, ".repo");
228+
certainlyMkdirs(repo0);
229+
File sub1 = new File(repoRoot, "sub1");
230+
certainlyMkdirs(sub1);
231+
File repo1 = new File(sub1, ".git");
232+
certainlyMkdirs(repo1);
233+
File sub2 = new File(sub1, "sub2");
234+
certainlyMkdirs(sub2);
235+
File repo2 = new File(sub2, ".git");
236+
certainlyMkdirs(repo2);
237+
238+
HistoryGuru instance = HistoryGuru.getInstance();
239+
Collection<RepositoryInfo> addedRepos = instance.addRepositories(
240+
Collections.singleton(Paths.get(repository.getSourceRoot(),
241+
"repoRoot").toString()), env.getIgnoredNames());
242+
assertEquals("should add to default nesting maximum", 2, addedRepos.size());
243+
244+
env.setNestingMaximum(2);
245+
addedRepos = instance.addRepositories(
246+
Collections.singleton(Paths.get(repository.getSourceRoot(),
247+
"repoRoot").toString()), env.getIgnoredNames());
248+
assertEquals("should get one more repo", 3, addedRepos.size());
249+
}
250+
251+
private static void certainlyMkdirs(File file) throws IOException {
252+
if (!file.mkdirs()) {
253+
throw new IOException("Couldn't mkdirs " + file);
254+
}
255+
}
214256
}

opengrok-web/src/main/java/org/opengrok/web/api/v1/controller/ProjectsController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public void deleteProjectData(@PathParam("project") String projectName) throws H
208208

209209
@DELETE
210210
@Path("/{project}/historycache")
211-
public void deleteHistoryCache(@PathParam("project") String projectName) throws HistoryException {
211+
public void deleteHistoryCache(@PathParam("project") String projectName) {
212212
// Avoid classification as a taint bug.
213213
projectName = Laundromat.launderInput(projectName);
214214

0 commit comments

Comments
 (0)