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/utils/JGitUtils.java |  143 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 129 insertions(+), 14 deletions(-)

diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java
index 72e948c..9d2e471 100644
--- a/src/com/gitblit/utils/JGitUtils.java
+++ b/src/com/gitblit/utils/JGitUtils.java
@@ -20,7 +20,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.Charset;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -30,12 +29,14 @@
 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;
 
 import org.eclipse.jgit.api.CloneCommand;
 import org.eclipse.jgit.api.FetchCommand;
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.diff.DiffEntry;
 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
 import org.eclipse.jgit.diff.DiffFormatter;
@@ -258,8 +259,12 @@
 	 * @return Repository
 	 */
 	public static Repository createRepository(File repositoriesFolder, String name) {
-		Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(true).call();
-		return git.getRepository();
+		try {
+			Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(true).call();
+			return git.getRepository();
+		} catch (GitAPIException e) {
+			throw new RuntimeException(e);
+		}
 	}
 
 	/**
@@ -271,16 +276,20 @@
 	 *            false all repositories are included.
 	 * @param searchSubfolders
 	 *            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) {
+			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));
+				onlyBare, searchSubfolders, depth, exclusions));
 		StringUtils.sortRepositorynames(list);
 		return list;
 	}
@@ -297,25 +306,61 @@
 	 *            repositories are included.
 	 * @param searchSubfolders
 	 *            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) {
+			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")) {
 						continue;
 					}
-					// determine repository name relative to base path
-					String repository = FileUtils.getRelativePath(baseFile, file);
-					list.add(repository);
+					if (gitDir.equals(file) || gitDir.getParentFile().equals(file)) {
+						// determine repository name relative to base path
+						String repository = FileUtils.getRelativePath(baseFile, file);
+						list.add(repository);
+					} else if (searchSubfolders && file.canRead()) {
+						// look for repositories in subfolders
+						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));
+					list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders,
+							nextDepth, exclusions));
 				}
 			}
 		}
@@ -543,14 +588,15 @@
 	 * @param tree
 	 *            if null, the RevTree from HEAD is assumed.
 	 * @param blobPath
+	 * @param charsets optional
 	 * @return UTF-8 string content
 	 */
-	public static String getStringContent(Repository repository, RevTree tree, String blobPath) {
+	public static String getStringContent(Repository repository, RevTree tree, String blobPath, String... charsets) {
 		byte[] content = getByteContent(repository, tree, blobPath);
 		if (content == null) {
 			return null;
 		}
-		return new String(content, Charset.forName(Constants.CHARACTER_ENCODING));
+		return StringUtils.decodeString(content, charsets);
 	}
 
 	/**
@@ -589,14 +635,15 @@
 	 * 
 	 * @param repository
 	 * @param objectId
+	 * @param charsets optional
 	 * @return UTF-8 string content
 	 */
-	public static String getStringContent(Repository repository, String objectId) {
+	public static String getStringContent(Repository repository, String objectId, String... charsets) {
 		byte[] content = getByteContent(repository, objectId);
 		if (content == null) {
 			return null;
 		}
-		return new String(content, Charset.forName(Constants.CHARACTER_ENCODING));
+		return StringUtils.decodeString(content, charsets);
 	}
 
 	/**
@@ -1223,6 +1270,74 @@
 	}
 	
 	/**
+	 * Sets the local branch ref to point to the specified commit id.
+	 *
+	 * @param repository
+	 * @param branch
+	 * @param commitId
+	 * @return true if successful
+	 */
+	public static boolean setBranchRef(Repository repository, String branch, String commitId) {
+		String branchName = branch;
+		if (!branchName.startsWith(Constants.R_HEADS)) {
+			branchName = Constants.R_HEADS + branch;
+		}
+
+		try {
+			RefUpdate refUpdate = repository.updateRef(branchName, false);
+			refUpdate.setNewObjectId(ObjectId.fromString(commitId));
+			RefUpdate.Result result = refUpdate.forceUpdate();
+
+			switch (result) {
+			case NEW:
+			case FORCED:
+			case NO_CHANGE:
+			case FAST_FORWARD:
+				return true;				
+			default:
+				LOGGER.error(MessageFormat.format("{0} {1} update to {2} returned result {3}",
+						repository.getDirectory().getAbsolutePath(), branchName, commitId, result));
+			}
+		} catch (Throwable t) {
+			error(t, repository, "{0} failed to set {1} to {2}", branchName, commitId);
+		}
+		return false;
+	}
+	
+	/**
+	 * Deletes the specified branch ref.
+	 *  
+	 * @param repository
+	 * @param branch
+	 * @return true if successful
+	 */
+	public static boolean deleteBranchRef(Repository repository, String branch) {
+		String branchName = branch;
+		if (!branchName.startsWith(Constants.R_HEADS)) {
+			branchName = Constants.R_HEADS + branch;
+		}
+
+		try {
+			RefUpdate refUpdate = repository.updateRef(branchName, false);
+			refUpdate.setForceUpdate(true);
+			RefUpdate.Result result = refUpdate.delete();
+			switch (result) {
+			case NEW:
+			case FORCED:
+			case NO_CHANGE:
+			case FAST_FORWARD:
+				return true;				
+			default:
+				LOGGER.error(MessageFormat.format("{0} failed to delete to {1} returned result {2}",
+						repository.getDirectory().getAbsolutePath(), branchName, result));
+			}
+		} catch (Throwable t) {
+			error(t, repository, "{0} failed to delete {1}", branchName);
+		}
+		return false;
+	}
+	
+	/**
 	 * Get the full branch and tag ref names for any potential HEAD targets.
 	 *
 	 * @param repository

--
Gitblit v1.9.1