Add recursive option to gitiles tree JSON In recursive mode, the tree entries are walked so the final JSON only contains non-tree objects. The name is analogous to git-ls-tree -r[ecurse]. Change-Id: I61fa14214280822b36ba28b53d1393fa93749645
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java index d570dbc..e0cc53e 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java
@@ -133,7 +133,7 @@ Repository repo = ServletUtils.getRepository(req); try (RevWalk rw = new RevWalk(repo); - WalkResult wr = WalkResult.forPath(rw, view)) { + WalkResult wr = WalkResult.forPath(rw, view, false)) { if (wr == null) { res.setStatus(SC_NOT_FOUND); return; @@ -168,7 +168,7 @@ Repository repo = ServletUtils.getRepository(req); try (RevWalk rw = new RevWalk(repo); - WalkResult wr = WalkResult.forPath(rw, view)) { + WalkResult wr = WalkResult.forPath(rw, view, false)) { if (wr == null) { res.setStatus(SC_NOT_FOUND); return; @@ -246,8 +246,14 @@ (longStr != null) && (longStr.isEmpty() || Boolean.TRUE.equals(StringUtils.toBooleanOrNull(longStr))); + String recursiveStr = req.getParameter("recursive"); + boolean recursive = + (recursiveStr != null) + && (recursiveStr.isEmpty() + || Boolean.TRUE.equals(StringUtils.toBooleanOrNull(recursiveStr))); + try (RevWalk rw = new RevWalk(repo); - WalkResult wr = WalkResult.forPath(rw, view)) { + WalkResult wr = WalkResult.forPath(rw, view, recursive)) { if (wr == null) { res.setStatus(SC_NOT_FOUND); return; @@ -257,7 +263,7 @@ renderJson( req, res, - TreeJsonData.toJsonData(wr.id, wr.tw, includeSizes), + TreeJsonData.toJsonData(wr.id, wr.tw, includeSizes, recursive), TreeJsonData.Tree.class); break; default: @@ -297,6 +303,7 @@ @Override public boolean include(TreeWalk tw) throws MissingObjectException, IncorrectObjectTypeException, IOException { + count++; int cmp = tw.isPathPrefix(pathRaw, pathRaw.length); if (cmp > 0) { @@ -352,7 +359,42 @@ * Includes information to help the auto-dive routine as well. */ private static class WalkResult implements AutoCloseable { - private static WalkResult forPath(RevWalk rw, GitilesView view) throws IOException { + private static WalkResult recursivePath(RevWalk rw, GitilesView view) throws IOException { + RevTree root = getRoot(view, rw); + String path = view.getPathPart(); + + TreeWalk tw; + if (!path.isEmpty()) { + try (TreeWalk toRoot = TreeWalk.forPath(rw.getObjectReader(), path, root)) { + if (toRoot == null) { + return null; + } + + ObjectId treeSHA = toRoot.getObjectId(0); + + ObjectLoader treeLoader = rw.getObjectReader().open(treeSHA); + if (treeLoader.getType() != Constants.OBJ_TREE) { + return null; + } + + tw = new TreeWalk(rw.getObjectReader()); + tw.addTree(treeSHA); + } + } else { + tw = new TreeWalk(rw.getObjectReader()); + tw.addTree(root); + } + + tw.setRecursive(true); + return new WalkResult(tw, path, root, root, FileType.TREE, ImmutableList.<Boolean>of()); + } + + private static WalkResult forPath(RevWalk rw, GitilesView view, boolean recursive) + throws IOException { + if (recursive) { + return recursivePath(rw, view); + } + RevTree root = getRoot(view, rw); String path = view.getPathPart(); TreeWalk tw = new TreeWalk(rw.getObjectReader());
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/TreeJsonData.java b/gitiles-servlet/src/main/java/com/google/gitiles/TreeJsonData.java index 6fb4a6c..70dcf9a 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/TreeJsonData.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/TreeJsonData.java
@@ -46,7 +46,8 @@ @Nullable Long size; } - static Tree toJsonData(ObjectId id, TreeWalk tw, boolean includeSizes) throws IOException { + static Tree toJsonData(ObjectId id, TreeWalk tw, boolean includeSizes, boolean recursive) + throws IOException { Tree tree = new Tree(); tree.id = id.name(); tree.entries = Lists.newArrayList(); @@ -56,7 +57,7 @@ e.mode = mode.getBits(); e.type = Constants.typeString(mode.getObjectType()); e.id = tw.getObjectId(0).name(); - e.name = tw.getNameString(); + e.name = recursive ? tw.getPathString() : tw.getNameString(); if (includeSizes) { if ((mode.getBits() & FileMode.TYPE_MASK) == FileMode.TYPE_FILE) {
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java index 1eac476..696b446 100644 --- a/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java +++ b/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java
@@ -268,6 +268,33 @@ } @Test + public void treeJsonRecursive() throws Exception { + RevCommit c = + repo.parseBody( + repo.branch("master") + .commit() + .add("foo/baz/bar/a", "bar contents") + .add("foo/baz/bar/b", "bar contents") + .add("baz", "baz contents") + .create()); + Tree tree = buildJson(Tree.class, "/repo/+/master/", "recursive=1"); + + assertThat(tree.id).isEqualTo(c.getTree().name()); + assertThat(tree.entries).hasSize(3); + + assertThat(tree.entries.get(0).name).isEqualTo("baz"); + assertThat(tree.entries.get(1).name).isEqualTo("foo/baz/bar/a"); + assertThat(tree.entries.get(2).name).isEqualTo("foo/baz/bar/b"); + + tree = buildJson(Tree.class, "/repo/+/master/foo/baz", "recursive=1"); + + assertThat(tree.entries).hasSize(2); + + assertThat(tree.entries.get(0).name).isEqualTo("bar/a"); + assertThat(tree.entries.get(1).name).isEqualTo("bar/b"); + } + + @Test public void treeJson() throws Exception { RevCommit c = repo.parseBody(