import java.util.Map.Entry;\r
import java.util.regex.Pattern;\r
\r
+import com.google.common.base.Strings;\r
import org.apache.commons.io.filefilter.TrueFileFilter;\r
import org.eclipse.jgit.api.CloneCommand;\r
import org.eclipse.jgit.api.FetchCommand;\r
return list;\r
}\r
\r
+ /**\r
+ * Returns the list of files in the specified folder at the specified\r
+ * commit. If the repository does not exist or is empty, an empty list is\r
+ * returned.\r
+ *\r
+ * This is modified version that implements path compression feature.\r
+ *\r
+ * @param repository\r
+ * @param path\r
+ * if unspecified, root folder is assumed.\r
+ * @param commit\r
+ * if null, HEAD is assumed.\r
+ * @return list of files in specified path\r
+ */\r
+ public static List<PathModel> getFilesInPath2(Repository repository, String path, RevCommit commit) {\r
+\r
+ List<PathModel> list = new ArrayList<PathModel>();\r
+ if (!hasCommits(repository)) {\r
+ return list;\r
+ }\r
+ if (commit == null) {\r
+ commit = getCommit(repository, null);\r
+ }\r
+ final TreeWalk tw = new TreeWalk(repository);\r
+ try {\r
+\r
+ tw.addTree(commit.getTree());\r
+ final boolean isPathEmpty = Strings.isNullOrEmpty(path);\r
+\r
+ if (!isPathEmpty) {\r
+ PathFilter f = PathFilter.create(path);\r
+ tw.setFilter(f);\r
+ }\r
+\r
+ tw.setRecursive(true);\r
+ List<String> paths = new ArrayList<>();\r
+\r
+ while (tw.next()) {\r
+ String child = isPathEmpty ? tw.getPathString()\r
+ : tw.getPathString().replaceFirst(String.format("%s/", path), "");\r
+ paths.add(child);\r
+ }\r
+\r
+ for(String p: PathUtils.compressPaths(paths)) {\r
+ String pathString = isPathEmpty ? p : String.format("%s/%s", path, p);\r
+ list.add(getPathModel(repository, pathString, path, commit));\r
+ }\r
+\r
+ } catch (IOException e) {\r
+ error(e, repository, "{0} failed to get files for commit {1}", commit.getName());\r
+ } finally {\r
+ tw.release();\r
+ }\r
+ Collections.sort(list);\r
+ return list;\r
+ }\r
+\r
/**\r
* Returns the list of files changed in a specified commit. If the\r
* repository does not exist or is empty, an empty list is returned.\r
objectId.getName(), commit.getName());\r
}\r
\r
+ /**\r
+ * Returns a path model by path string\r
+ *\r
+ * @param repo\r
+ * @param path\r
+ * @param filter\r
+ * @param commit\r
+ * @return a path model of the specified object\r
+ */\r
+ private static PathModel getPathModel(Repository repo, String path, String filter, RevCommit commit)\r
+ throws IOException {\r
+\r
+ long size = 0;\r
+ TreeWalk tw = TreeWalk.forPath(repo, path, commit.getTree());\r
+ String pathString = path;\r
+\r
+ if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {\r
+ size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB);\r
+ pathString = PathUtils.getLastPathComponent(pathString);\r
+\r
+ } else if (tw.isSubtree()) {\r
+\r
+ // do not display dirs that are behind in the path\r
+ if (!Strings.isNullOrEmpty(filter)) {\r
+ pathString = path.replaceFirst(filter + "/", "");\r
+ }\r
+\r
+ // remove the last slash from path in displayed link\r
+ if (pathString != null && pathString.charAt(pathString.length()-1) == '/') {\r
+ pathString = pathString.substring(0, pathString.length()-1);\r
+ }\r
+ }\r
+\r
+ return new PathModel(pathString, tw.getPathString(), size, tw.getFileMode(0).getBits(),\r
+ tw.getObjectId(0).getName(), commit.getName());\r
+\r
+\r
+ }\r
+\r
+\r
/**\r
* Returns a permissions representation of the mode bits.\r
*\r
}\r
return false;\r
}\r
-
- /**
- * Returns true if the commit identified by commitId is an ancestor or the
- * the commit identified by tipId.
- *
- * @param repository
- * @param commitId
- * @param tipId
- * @return true if there is the commit is an ancestor of the tip
- */
- public static boolean isMergedInto(Repository repository, String commitId, String tipId) {
- try {
- return isMergedInto(repository, repository.resolve(commitId), repository.resolve(tipId));
- } catch (Exception e) {
- LOGGER.error("Failed to determine isMergedInto", e);
- }
- return false;
- }
-
- /**
- * Returns true if the commit identified by commitId is an ancestor or the
- * the commit identified by tipId.
- *
- * @param repository
- * @param commitId
- * @param tipId
- * @return true if there is the commit is an ancestor of the tip
- */
- public static boolean isMergedInto(Repository repository, ObjectId commitId, ObjectId tipCommitId) {
- // traverse the revlog looking for a commit chain between the endpoints
- RevWalk rw = new RevWalk(repository);
- try {
- // must re-lookup RevCommits to workaround undocumented RevWalk bug
- RevCommit tip = rw.lookupCommit(tipCommitId);
- RevCommit commit = rw.lookupCommit(commitId);
- return rw.isMergedInto(commit, tip);
- } catch (Exception e) {
- LOGGER.error("Failed to determine isMergedInto", e);
- } finally {
- rw.dispose();
- }
- return false;
- }
-
- /**
- * Returns the merge base of two commits or null if there is no common
- * ancestry.
- *
- * @param repository
- * @param commitIdA
- * @param commitIdB
- * @return the commit id of the merge base or null if there is no common base
- */
- public static String getMergeBase(Repository repository, ObjectId commitIdA, ObjectId commitIdB) {
- RevWalk rw = new RevWalk(repository);
- try {
- RevCommit a = rw.lookupCommit(commitIdA);
- RevCommit b = rw.lookupCommit(commitIdB);
-
- rw.setRevFilter(RevFilter.MERGE_BASE);
- rw.markStart(a);
- rw.markStart(b);
- RevCommit mergeBase = rw.next();
- if (mergeBase == null) {
- return null;
- }
- return mergeBase.getName();
- } catch (Exception e) {
- LOGGER.error("Failed to determine merge base", e);
- } finally {
- rw.dispose();
- }
- return null;
- }
-
- public static enum MergeStatus {
- MISSING_INTEGRATION_BRANCH, MISSING_SRC_BRANCH, NOT_MERGEABLE, FAILED, ALREADY_MERGED, MERGEABLE, MERGED;
- }
-
- /**
- * Determines if we can cleanly merge one branch into another. Returns true
- * if we can merge without conflict, otherwise returns false.
- *
- * @param repository
- * @param src
- * @param toBranch
- * @return true if we can merge without conflict
- */
- public static MergeStatus canMerge(Repository repository, String src, String toBranch) {
- RevWalk revWalk = null;
- try {
+\r
+ /**\r
+ * Returns true if the commit identified by commitId is an ancestor or the\r
+ * the commit identified by tipId.\r
+ *\r
+ * @param repository\r
+ * @param commitId\r
+ * @param tipId\r
+ * @return true if there is the commit is an ancestor of the tip\r
+ */\r
+ public static boolean isMergedInto(Repository repository, String commitId, String tipId) {\r
+ try {\r
+ return isMergedInto(repository, repository.resolve(commitId), repository.resolve(tipId));\r
+ } catch (Exception e) {\r
+ LOGGER.error("Failed to determine isMergedInto", e);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Returns true if the commit identified by commitId is an ancestor or the\r
+ * the commit identified by tipId.\r
+ *\r
+ * @param repository\r
+ * @param commitId\r
+ * @param tipId\r
+ * @return true if there is the commit is an ancestor of the tip\r
+ */\r
+ public static boolean isMergedInto(Repository repository, ObjectId commitId, ObjectId tipCommitId) {\r
+ // traverse the revlog looking for a commit chain between the endpoints\r
+ RevWalk rw = new RevWalk(repository);\r
+ try {\r
+ // must re-lookup RevCommits to workaround undocumented RevWalk bug\r
+ RevCommit tip = rw.lookupCommit(tipCommitId);\r
+ RevCommit commit = rw.lookupCommit(commitId);\r
+ return rw.isMergedInto(commit, tip);\r
+ } catch (Exception e) {\r
+ LOGGER.error("Failed to determine isMergedInto", e);\r
+ } finally {\r
+ rw.dispose();\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Returns the merge base of two commits or null if there is no common\r
+ * ancestry.\r
+ *\r
+ * @param repository\r
+ * @param commitIdA\r
+ * @param commitIdB\r
+ * @return the commit id of the merge base or null if there is no common base\r
+ */\r
+ public static String getMergeBase(Repository repository, ObjectId commitIdA, ObjectId commitIdB) {\r
+ RevWalk rw = new RevWalk(repository);\r
+ try {\r
+ RevCommit a = rw.lookupCommit(commitIdA);\r
+ RevCommit b = rw.lookupCommit(commitIdB);\r
+\r
+ rw.setRevFilter(RevFilter.MERGE_BASE);\r
+ rw.markStart(a);\r
+ rw.markStart(b);\r
+ RevCommit mergeBase = rw.next();\r
+ if (mergeBase == null) {\r
+ return null;\r
+ }\r
+ return mergeBase.getName();\r
+ } catch (Exception e) {\r
+ LOGGER.error("Failed to determine merge base", e);\r
+ } finally {\r
+ rw.dispose();\r
+ }\r
+ return null;\r
+ }\r
+\r
+ public static enum MergeStatus {\r
+ MISSING_INTEGRATION_BRANCH, MISSING_SRC_BRANCH, NOT_MERGEABLE, FAILED, ALREADY_MERGED, MERGEABLE, MERGED;\r
+ }\r
+\r
+ /**\r
+ * Determines if we can cleanly merge one branch into another. Returns true\r
+ * if we can merge without conflict, otherwise returns false.\r
+ *\r
+ * @param repository\r
+ * @param src\r
+ * @param toBranch\r
+ * @return true if we can merge without conflict\r
+ */\r
+ public static MergeStatus canMerge(Repository repository, String src, String toBranch) {\r
+ RevWalk revWalk = null;\r
+ try {\r
revWalk = new RevWalk(repository);\r
ObjectId branchId = repository.resolve(toBranch);\r
if (branchId == null) {\r
if (srcId == null) {\r
return MergeStatus.MISSING_SRC_BRANCH;\r
}\r
- RevCommit branchTip = revWalk.lookupCommit(branchId);
- RevCommit srcTip = revWalk.lookupCommit(srcId);
- if (revWalk.isMergedInto(srcTip, branchTip)) {
- // already merged
- return MergeStatus.ALREADY_MERGED;
- } else if (revWalk.isMergedInto(branchTip, srcTip)) {
- // fast-forward
- return MergeStatus.MERGEABLE;
- }
- RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);
- boolean canMerge = merger.merge(branchTip, srcTip);
- if (canMerge) {
- return MergeStatus.MERGEABLE;
- }
+ RevCommit branchTip = revWalk.lookupCommit(branchId);\r
+ RevCommit srcTip = revWalk.lookupCommit(srcId);\r
+ if (revWalk.isMergedInto(srcTip, branchTip)) {\r
+ // already merged\r
+ return MergeStatus.ALREADY_MERGED;\r
+ } else if (revWalk.isMergedInto(branchTip, srcTip)) {\r
+ // fast-forward\r
+ return MergeStatus.MERGEABLE;\r
+ }\r
+ RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);\r
+ boolean canMerge = merger.merge(branchTip, srcTip);\r
+ if (canMerge) {\r
+ return MergeStatus.MERGEABLE;\r
+ }\r
} catch (NullPointerException e) {\r
LOGGER.error("Failed to determine canMerge", e);\r
- } catch (IOException e) {
- LOGGER.error("Failed to determine canMerge", e);
+ } catch (IOException e) {\r
+ LOGGER.error("Failed to determine canMerge", e);\r
} finally {\r
- if (revWalk != null) {
+ if (revWalk != null) {\r
revWalk.release();\r
- }
- }
- return MergeStatus.NOT_MERGEABLE;
- }
-
-
- public static class MergeResult {
- public final MergeStatus status;
- public final String sha;
-
- MergeResult(MergeStatus status, String sha) {
- this.status = status;
- this.sha = sha;
- }
- }
-
- /**
- * Tries to merge a commit into a branch. If there are conflicts, the merge
- * will fail.
- *
- * @param repository
- * @param src
- * @param toBranch
- * @param committer
- * @param message
- * @return the merge result
- */
- public static MergeResult merge(Repository repository, String src, String toBranch,
- PersonIdent committer, String message) {
-
- if (!toBranch.startsWith(Constants.R_REFS)) {
- // branch ref doesn't start with ref, assume this is a branch head
- toBranch = Constants.R_HEADS + toBranch;
- }
-
- RevWalk revWalk = null;
- try {
- revWalk = new RevWalk(repository);
- RevCommit branchTip = revWalk.lookupCommit(repository.resolve(toBranch));
- RevCommit srcTip = revWalk.lookupCommit(repository.resolve(src));
- if (revWalk.isMergedInto(srcTip, branchTip)) {
- // already merged
- return new MergeResult(MergeStatus.ALREADY_MERGED, null);
- }
- RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);
- boolean merged = merger.merge(branchTip, srcTip);
- if (merged) {
- // create a merge commit and a reference to track the merge commit
- ObjectId treeId = merger.getResultTreeId();
- ObjectInserter odi = repository.newObjectInserter();
- try {
- // Create a commit object
- CommitBuilder commitBuilder = new CommitBuilder();
- commitBuilder.setCommitter(committer);
- commitBuilder.setAuthor(committer);
- commitBuilder.setEncoding(Constants.CHARSET);
- if (StringUtils.isEmpty(message)) {
- message = MessageFormat.format("merge {0} into {1}", srcTip.getName(), branchTip.getName());
- }
- commitBuilder.setMessage(message);
- commitBuilder.setParentIds(branchTip.getId(), srcTip.getId());
- commitBuilder.setTreeId(treeId);
-
- // Insert the merge commit into the repository
- ObjectId mergeCommitId = odi.insert(commitBuilder);
- odi.flush();
-
- // set the merge ref to the merge commit
- RevCommit mergeCommit = revWalk.parseCommit(mergeCommitId);
- RefUpdate mergeRefUpdate = repository.updateRef(toBranch);
- mergeRefUpdate.setNewObjectId(mergeCommitId);
- mergeRefUpdate.setRefLogMessage("commit: " + mergeCommit.getShortMessage(), false);
- RefUpdate.Result rc = mergeRefUpdate.update();
- switch (rc) {
- case FAST_FORWARD:
- // successful, clean merge
+ }\r
+ }\r
+ return MergeStatus.NOT_MERGEABLE;\r
+ }\r
+\r
+\r
+ public static class MergeResult {\r
+ public final MergeStatus status;\r
+ public final String sha;\r
+\r
+ MergeResult(MergeStatus status, String sha) {\r
+ this.status = status;\r
+ this.sha = sha;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Tries to merge a commit into a branch. If there are conflicts, the merge\r
+ * will fail.\r
+ *\r
+ * @param repository\r
+ * @param src\r
+ * @param toBranch\r
+ * @param committer\r
+ * @param message\r
+ * @return the merge result\r
+ */\r
+ public static MergeResult merge(Repository repository, String src, String toBranch,\r
+ PersonIdent committer, String message) {\r
+\r
+ if (!toBranch.startsWith(Constants.R_REFS)) {\r
+ // branch ref doesn't start with ref, assume this is a branch head\r
+ toBranch = Constants.R_HEADS + toBranch;\r
+ }\r
+\r
+ RevWalk revWalk = null;\r
+ try {\r
+ revWalk = new RevWalk(repository);\r
+ RevCommit branchTip = revWalk.lookupCommit(repository.resolve(toBranch));\r
+ RevCommit srcTip = revWalk.lookupCommit(repository.resolve(src));\r
+ if (revWalk.isMergedInto(srcTip, branchTip)) {\r
+ // already merged\r
+ return new MergeResult(MergeStatus.ALREADY_MERGED, null);\r
+ }\r
+ RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);\r
+ boolean merged = merger.merge(branchTip, srcTip);\r
+ if (merged) {\r
+ // create a merge commit and a reference to track the merge commit\r
+ ObjectId treeId = merger.getResultTreeId();\r
+ ObjectInserter odi = repository.newObjectInserter();\r
+ try {\r
+ // Create a commit object\r
+ CommitBuilder commitBuilder = new CommitBuilder();\r
+ commitBuilder.setCommitter(committer);\r
+ commitBuilder.setAuthor(committer);\r
+ commitBuilder.setEncoding(Constants.CHARSET);\r
+ if (StringUtils.isEmpty(message)) {\r
+ message = MessageFormat.format("merge {0} into {1}", srcTip.getName(), branchTip.getName());\r
+ }\r
+ commitBuilder.setMessage(message);\r
+ commitBuilder.setParentIds(branchTip.getId(), srcTip.getId());\r
+ commitBuilder.setTreeId(treeId);\r
+\r
+ // Insert the merge commit into the repository\r
+ ObjectId mergeCommitId = odi.insert(commitBuilder);\r
+ odi.flush();\r
+\r
+ // set the merge ref to the merge commit\r
+ RevCommit mergeCommit = revWalk.parseCommit(mergeCommitId);\r
+ RefUpdate mergeRefUpdate = repository.updateRef(toBranch);\r
+ mergeRefUpdate.setNewObjectId(mergeCommitId);\r
+ mergeRefUpdate.setRefLogMessage("commit: " + mergeCommit.getShortMessage(), false);\r
+ RefUpdate.Result rc = mergeRefUpdate.update();\r
+ switch (rc) {\r
+ case FAST_FORWARD:\r
+ // successful, clean merge\r
break;\r
- default:
- throw new GitBlitException(MessageFormat.format("Unexpected result \"{0}\" when merging commit {1} into {2} in {3}",
- rc.name(), srcTip.getName(), branchTip.getName(), repository.getDirectory()));
- }
-
- // return the merge commit id
- return new MergeResult(MergeStatus.MERGED, mergeCommitId.getName());
- } finally {
- odi.release();
- }
- }
- } catch (IOException e) {
- LOGGER.error("Failed to merge", e);
+ default:\r
+ throw new GitBlitException(MessageFormat.format("Unexpected result \"{0}\" when merging commit {1} into {2} in {3}",\r
+ rc.name(), srcTip.getName(), branchTip.getName(), repository.getDirectory()));\r
+ }\r
+\r
+ // return the merge commit id\r
+ return new MergeResult(MergeStatus.MERGED, mergeCommitId.getName());\r
+ } finally {\r
+ odi.release();\r
+ }\r
+ }\r
+ } catch (IOException e) {\r
+ LOGGER.error("Failed to merge", e);\r
} finally {\r
- if (revWalk != null) {
+ if (revWalk != null) {\r
revWalk.release();\r
- }
- }
- return new MergeResult(MergeStatus.FAILED, null);
- }
+ }\r
+ }\r
+ return new MergeResult(MergeStatus.FAILED, null);\r
+ }\r
}\r