From 0adceb4b64dfe0dd509da33c6d733a47fbf803a2 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Wed, 01 Aug 2012 21:21:32 -0400
Subject: [PATCH] Regex exclusions for repository search (issue 103)

---
 src/com/gitblit/GitBlit.java               |    3 +
 docs/04_releases.mkd                       |    5 ++
 tests/com/gitblit/tests/JGitUtilsTest.java |   24 ++++++++++-
 src/com/gitblit/AddIndexedBranch.java      |    2 
 distrib/gitblit.properties                 |   10 +++++
 src/com/gitblit/utils/JGitUtils.java       |   38 ++++++++++++++++--
 6 files changed, 71 insertions(+), 11 deletions(-)

diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties
index f06aaef..0923c41 100644
--- a/distrib/gitblit.properties
+++ b/distrib/gitblit.properties
@@ -27,6 +27,16 @@
 # SINCE 1.0.1
 git.searchRecursionDepth = -1
 
+# List of regex exclusion patterns to match against folders found in
+# *git.repositoriesFolder*.
+# Use forward slashes even on Windows!!
+# e.g. test/jgit\.git
+#
+# SPACE-DELIMITED
+# CASE-SENSITIVE
+# SINCE 1.0.1
+git.searchExclusions =
+
 # Allow push/pull over http/https with JGit servlet.
 # If you do NOT want to allow Git clients to clone/push to Gitblit set this
 # to false.  You might want to do this if you are only using ssh:// or git://.
diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd
index 8a08435..e197210 100644
--- a/docs/04_releases.mkd
+++ b/docs/04_releases.mkd
@@ -18,7 +18,10 @@
 
 #### changes
 
-- Added *git.searchRecursionDepth=-1* to control how deep Gitblit will recurse into *git.repositoriesFolder* looking for repositories (issue 103)
+- Added setting to control how deep Gitblit will recurse into *git.repositoriesFolder* looking for repositories (issue 103)
+    **New:** *git.searchRecursionDepth=-1*  
+- Added setting to specify regex exclusions for repositories (issue 103)
+    **New:** *git.searchExclusions=*  
 - Blob page now supports displaying images (issue 6)
 - Non-image binary files can now be downloaded using the RAW link
 - Updated Polish translation
diff --git a/src/com/gitblit/AddIndexedBranch.java b/src/com/gitblit/AddIndexedBranch.java
index 8ead17e..6699706 100644
--- a/src/com/gitblit/AddIndexedBranch.java
+++ b/src/com/gitblit/AddIndexedBranch.java
@@ -63,7 +63,7 @@
 		
 		// determine available repositories
 		File folder = new File(params.folder);
-		List<String> repoList = JGitUtils.getRepositoryList(folder, false, true, -1);
+		List<String> repoList = JGitUtils.getRepositoryList(folder, false, true, -1, null);
 		
 		int modCount = 0;
 		int skipCount = 0;
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index d4a59d5..8f51069 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -743,7 +743,8 @@
 		return JGitUtils.getRepositoryList(repositoriesFolder, 
 				settings.getBoolean(Keys.git.onlyAccessBareRepositories, false),
 				settings.getBoolean(Keys.git.searchRepositoriesSubfolders, true),
-				settings.getInteger(Keys.git.searchRecursionDepth, -1));
+				settings.getInteger(Keys.git.searchRecursionDepth, -1),
+				settings.getStrings(Keys.git.searchExclusions));
 	}
 
 	/**
diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java
index ff701b3..9d2e471 100644
--- a/src/com/gitblit/utils/JGitUtils.java
+++ b/src/com/gitblit/utils/JGitUtils.java
@@ -29,6 +29,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
@@ -277,16 +278,18 @@
 	 *            recurse into subfolders to find grouped repositories
 	 * @param depth
 	 *            optional recursion depth, -1 = infinite recursion
+	 * @param exclusions
+	 *            list of regex exclusions for matching to folder names
 	 * @return list of repository names
 	 */
 	public static List<String> getRepositoryList(File repositoriesFolder, boolean onlyBare,
-			boolean searchSubfolders, int depth) {
+			boolean searchSubfolders, int depth, List<String> exclusions) {
 		List<String> list = new ArrayList<String>();
 		if (repositoriesFolder == null || !repositoriesFolder.exists()) {
 			return list;
 		}
 		list.addAll(getRepositoryList(repositoriesFolder.getAbsolutePath(), repositoriesFolder,
-				onlyBare, searchSubfolders, depth));
+				onlyBare, searchSubfolders, depth, exclusions));
 		StringUtils.sortRepositorynames(list);
 		return list;
 	}
@@ -305,18 +308,41 @@
 	 *            recurse into subfolders to find grouped repositories
 	 * @param depth
 	 *            recursion depth, -1 = infinite recursion
+	 * @param exclusions
+	 *            list of regex exclusions for matching to folder names
 	 * @return
 	 */
 	private static List<String> getRepositoryList(String basePath, File searchFolder,
-			boolean onlyBare, boolean searchSubfolders, int depth) {
+			boolean onlyBare, boolean searchSubfolders, int depth, List<String> exclusions) {
 		File baseFile = new File(basePath);
 		List<String> list = new ArrayList<String>();
 		if (depth == 0) {
 			return list;
 		}
+		List<Pattern> patterns = new ArrayList<Pattern>();
+		if (!ArrayUtils.isEmpty(exclusions)) {
+			for (String regex : exclusions) {
+				patterns.add(Pattern.compile(regex));
+			}
+		}
+		
 		int nextDepth = (depth == -1) ? -1 : depth - 1;
 		for (File file : searchFolder.listFiles()) {
 			if (file.isDirectory()) {
+				boolean exclude = false;
+				for (Pattern pattern : patterns) {
+					String path = FileUtils.getRelativePath(baseFile, file).replace('\\',  '/');
+					if (pattern.matcher(path).find()) {
+						LOGGER.debug(MessageFormat.format("excluding {0} because of rule {1}", path, pattern.pattern()));
+						exclude = true;
+						break;
+					}
+				}
+				if (exclude) {
+					// skip to next file
+					continue;
+				}
+
 				File gitDir = FileKey.resolve(new File(searchFolder, file.getName()), FS.DETECTED);
 				if (gitDir != null) {
 					if (onlyBare && gitDir.getName().equals(".git")) {
@@ -328,11 +354,13 @@
 						list.add(repository);
 					} else if (searchSubfolders && file.canRead()) {
 						// look for repositories in subfolders
-						list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders, nextDepth));
+						list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders,
+								nextDepth, exclusions));
 					}
 				} else if (searchSubfolders && file.canRead()) {
 					// look for repositories in subfolders
-					list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders, nextDepth));
+					list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders,
+							nextDepth, exclusions));
 				}
 			}
 		}
diff --git a/tests/com/gitblit/tests/JGitUtilsTest.java b/tests/com/gitblit/tests/JGitUtilsTest.java
index addc934..495a00b 100644
--- a/tests/com/gitblit/tests/JGitUtilsTest.java
+++ b/tests/com/gitblit/tests/JGitUtilsTest.java
@@ -67,15 +67,33 @@
 
 	@Test
 	public void testFindRepositories() {
-		List<String> list = JGitUtils.getRepositoryList(null, false, true, -1);
+		List<String> list = JGitUtils.getRepositoryList(null, false, true, -1, null);
 		assertEquals(0, list.size());
-		list.addAll(JGitUtils.getRepositoryList(new File("DoesNotExist"), true, true, -1));
+		list.addAll(JGitUtils.getRepositoryList(new File("DoesNotExist"), true, true, -1, null));
 		assertEquals(0, list.size());
-		list.addAll(JGitUtils.getRepositoryList(GitBlitSuite.REPOSITORIES, false, true, -1));
+		list.addAll(JGitUtils.getRepositoryList(GitBlitSuite.REPOSITORIES, false, true, -1, null));
 		assertTrue("No repositories found in " + GitBlitSuite.REPOSITORIES, list.size() > 0);
 	}
 
 	@Test
+	public void testFindExclusions() {
+		List<String> list = JGitUtils.getRepositoryList(GitBlitSuite.REPOSITORIES, false, true, -1, null);
+		assertTrue("Missing jgit repository?!", list.contains("test/jgit.git"));
+
+		list = JGitUtils.getRepositoryList(GitBlitSuite.REPOSITORIES, false, true, -1, Arrays.asList("test/jgit\\.git"));
+		assertFalse("Repository exclusion failed!", list.contains("test/jgit.git"));
+
+		list = JGitUtils.getRepositoryList(GitBlitSuite.REPOSITORIES, false, true, -1, Arrays.asList("test/*"));
+		assertFalse("Repository exclusion failed!", list.contains("test/jgit.git"));
+
+		list = JGitUtils.getRepositoryList(GitBlitSuite.REPOSITORIES, false, true, -1, Arrays.asList("(jgit)+"));
+		assertFalse("Repository exclusion failed!", list.contains("test/jgit.git"));
+		assertFalse("Repository exclusion failed!", list.contains("working/jgit"));
+		assertFalse("Repository exclusion failed!", list.contains("working/jgit2"));
+
+	}
+
+	@Test
 	public void testOpenRepository() throws Exception {
 		Repository repository = GitBlitSuite.getHelloworldRepository();
 		repository.close();

--
Gitblit v1.9.1