Add follow support to LogServlet Currently just adds a TreeFilter to the walk; there is not yet any indication in the HTML view that a rename occurred. Change-Id: Idacd5713155df6f616f1a72e09bce14e0463a80e
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java index ce9d38a..bcc09eb 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java
@@ -30,6 +30,7 @@ import com.google.gitiles.DateFormatter.Format; import com.google.gson.reflect.TypeToken; +import org.eclipse.jgit.diff.DiffConfig; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.RevWalkException; @@ -40,6 +41,7 @@ import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.FollowFilter; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevTag; @@ -72,8 +74,11 @@ static final String LIMIT_PARAM = "n"; static final String START_PARAM = "s"; - private static final String PRETTY_PARAM = "pretty"; + + private static final String FOLLOW_PARAM = "follow"; private static final String NAME_STATUS_PARAM = "name-status"; + private static final String PRETTY_PARAM = "pretty"; + private static final int DEFAULT_LIMIT = 100; private static final int MAX_LIMIT = 10000; @@ -88,14 +93,15 @@ protected void doGetHtml(HttpServletRequest req, HttpServletResponse res) throws IOException { Repository repo = ServletUtils.getRepository(req); GitilesView view = getView(req, repo); - Paginator paginator = newPaginator(repo, view); - if (paginator == null) { - res.setStatus(SC_NOT_FOUND); - return; - } + Paginator paginator = null; try { GitilesAccess access = getAccess(req); + paginator = newPaginator(repo, view, getAccess(req)); + if (paginator == null) { + res.setStatus(SC_NOT_FOUND); + return; + } DateFormatter df = new DateFormatter(access, Format.DEFAULT); // Allow the user to select a logView variant with the "pretty" param. @@ -134,7 +140,9 @@ res.setStatus(SC_INTERNAL_SERVER_ERROR); return; } finally { - paginator.getWalk().close(); + if (paginator != null) { + paginator.getWalk().close(); + } } } @@ -142,11 +150,6 @@ protected void doGetJson(HttpServletRequest req, HttpServletResponse res) throws IOException { Repository repo = ServletUtils.getRepository(req); GitilesView view = getView(req, repo); - Paginator paginator = newPaginator(repo, view); - if (paginator == null) { - res.setStatus(SC_NOT_FOUND); - return; - } Set<Field> fs = Sets.newEnumSet(CommitJsonData.DEFAULT_FIELDS, Field.class); String nameStatus = Iterables.getFirst(view.getParameters().get(NAME_STATUS_PARAM), null); @@ -154,7 +157,13 @@ fs.add(Field.DIFF_TREE); } + Paginator paginator = null; try { + paginator = newPaginator(repo, view, getAccess(req)); + if (paginator == null) { + res.setStatus(SC_NOT_FOUND); + return; + } DateFormatter df = new DateFormatter(getAccess(req), Format.DEFAULT); CommitJsonData.Log result = new CommitJsonData.Log(); List<CommitJsonData.Commit> entries = Lists.newArrayListWithCapacity(paginator.getLimit()); @@ -172,7 +181,9 @@ } renderJson(req, res, result, new TypeToken<CommitJsonData.Log>() {}.getType()); } finally { - paginator.getWalk().close(); + if (paginator != null) { + paginator.getWalk().close(); + } } } @@ -210,19 +221,14 @@ } } - private static RevWalk newWalk(Repository repo, GitilesView view) + private static RevWalk newWalk(Repository repo, GitilesView view, GitilesAccess access) throws MissingObjectException, IncorrectObjectTypeException, IOException { RevWalk walk = new RevWalk(repo); walk.markStart(walk.parseCommit(view.getRevision().getId())); if (view.getOldRevision() != Revision.NULL) { walk.markUninteresting(walk.parseCommit(view.getOldRevision().getId())); } - if (!Strings.isNullOrEmpty(view.getPathPart())) { - walk.setRewriteParents(false); - walk.setTreeFilter(AndTreeFilter.create( - PathFilterGroup.createFromStrings(view.getPathPart()), - TreeFilter.ANY_DIFF)); - } + setTreeFilter(walk, view, access); List<RevFilter> filters = new ArrayList<>(3); if (isTrue(Iterables.getFirst(view.getParameters().get("no-merges"), null))) { filters.add(RevFilter.NO_MERGES); @@ -243,6 +249,22 @@ return walk; } + private static void setTreeFilter(RevWalk walk, GitilesView view, GitilesAccess access) + throws IOException { + if (Strings.isNullOrEmpty(view.getPathPart())) { + return; + } + walk.setRewriteParents(false); + String path = view.getPathPart(); + if (isTrue(Iterables.getFirst(view.getParameters().get(FOLLOW_PARAM), null))) { + walk.setTreeFilter(FollowFilter.create(path, access.getConfig().get(DiffConfig.KEY))); + } else { + walk.setTreeFilter(AndTreeFilter.create( + PathFilterGroup.createFromStrings(view.getPathPart()), + TreeFilter.ANY_DIFF)); + } + } + private static boolean isTrue(String v) { if (v == null) { return false; @@ -252,14 +274,15 @@ return Boolean.TRUE.equals(StringUtils.toBooleanOrNull(v)); } - private static Paginator newPaginator(Repository repo, GitilesView view) throws IOException { + private static Paginator newPaginator(Repository repo, GitilesView view, GitilesAccess access) + throws IOException { if (view == null) { return null; } RevWalk walk = null; try { - walk = newWalk(repo, view); + walk = newWalk(repo, view, access); } catch (IncorrectObjectTypeException e) { return null; }
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/LogServletTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/LogServletTest.java index 893e259..56f1c29 100644 --- a/gitiles-servlet/src/test/java/com/google/gitiles/LogServletTest.java +++ b/gitiles-servlet/src/test/java/com/google/gitiles/LogServletTest.java
@@ -68,6 +68,31 @@ assertThat(jc1.treeDiff.get(0).newPath).isEqualTo("foo"); } + @Test + public void follow() throws Exception { + String contents = "contents"; + RevCommit c1 = repo.branch("master") + .commit() + .add("foo", contents) + .create(); + RevCommit c2 = repo.branch("master") + .commit() + .rm("foo") + .add("bar", contents) + .create(); + repo.getRevWalk().parseBody(c1); + repo.getRevWalk().parseBody(c2); + + Log response = buildJson(LOG, "/repo/+log/master/bar"); + assertThat(response.log).hasSize(1); + verifyJsonCommit(response.log.get(0), c2); + + response = buildJson(LOG, "/repo/+log/master/bar", "follow=1"); + assertThat(response.log).hasSize(2); + verifyJsonCommit(response.log.get(0), c2); + verifyJsonCommit(response.log.get(1), c1); + } + private void verifyJsonCommit(Commit jsonCommit, RevCommit commit) throws Exception { repo.getRevWalk().parseBody(commit); GitilesAccess access = new TestGitilesAccess(repo.getRepository()).forRequest(null);