Add support for "long" mode in JSON queries for trees. In long mode, the tree entries have a 'size' field for blob entries, and symlinks have a 'target' field. The query field is analogous to the ls-tree --long (-l) option. Change-Id: I16bd9f797cfadb457d0745f9699f701cac26ef19
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 4837671..d570dbc 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java
@@ -23,6 +23,7 @@ import static org.eclipse.jgit.lib.Constants.OBJ_TREE; import com.google.common.base.Joiner; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; @@ -53,6 +54,7 @@ import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.QuotedString; import org.eclipse.jgit.util.RawParseUtils; +import org.eclipse.jgit.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -239,6 +241,11 @@ GitilesView view = ViewFilter.getView(req); Repository repo = ServletUtils.getRepository(req); + String longStr = req.getParameter("long"); + boolean includeSizes = + (longStr != null) + && (longStr.isEmpty() || Boolean.TRUE.equals(StringUtils.toBooleanOrNull(longStr))); + try (RevWalk rw = new RevWalk(repo); WalkResult wr = WalkResult.forPath(rw, view)) { if (wr == null) { @@ -247,7 +254,11 @@ } switch (wr.type) { case TREE: - renderJson(req, res, TreeJsonData.toJsonData(wr.id, wr.tw), TreeJsonData.Tree.class); + renderJson( + req, + res, + TreeJsonData.toJsonData(wr.id, wr.tw, includeSizes), + TreeJsonData.Tree.class); break; default: res.setStatus(SC_NOT_FOUND);
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 b525453..6fb4a6c 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/TreeJsonData.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/TreeJsonData.java
@@ -14,11 +14,17 @@ package com.google.gitiles; +import static java.nio.charset.StandardCharsets.UTF_8; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.collect.Lists; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.TreeWalk; import java.io.IOException; @@ -35,9 +41,12 @@ String type; String id; String name; + + @Nullable String target; + @Nullable Long size; } - static Tree toJsonData(ObjectId id, TreeWalk tw) throws IOException { + static Tree toJsonData(ObjectId id, TreeWalk tw, boolean includeSizes) throws IOException { Tree tree = new Tree(); tree.id = id.name(); tree.entries = Lists.newArrayList(); @@ -48,6 +57,15 @@ e.type = Constants.typeString(mode.getObjectType()); e.id = tw.getObjectId(0).name(); e.name = tw.getNameString(); + + if (includeSizes) { + if ((mode.getBits() & FileMode.TYPE_MASK) == FileMode.TYPE_FILE) { + e.size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB); + } else if ((mode.getBits() & FileMode.TYPE_MASK) == FileMode.TYPE_SYMLINK) { + e.target = + new String(tw.getObjectReader().open(tw.getObjectId(0)).getCachedBytes(), UTF_8); + } + } tree.entries.add(e); } return tree;
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 5842e07..1eac476 100644 --- a/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java +++ b/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java
@@ -224,6 +224,50 @@ } @Test + public void treeJsonSizes() throws Exception { + RevCommit c = repo.parseBody(repo.branch("master").commit().add("baz", "01234567").create()); + + Tree tree = buildJson(Tree.class, "/repo/+/master/", "long=1"); + + assertThat(tree.id).isEqualTo(c.getTree().name()); + assertThat(tree.entries).hasSize(1); + assertThat(tree.entries.get(0).mode).isEqualTo(0100644); + assertThat(tree.entries.get(0).type).isEqualTo("blob"); + assertThat(tree.entries.get(0).name).isEqualTo("baz"); + assertThat(tree.entries.get(0).size).isEqualTo(8); + } + + @Test + public void treeJsonLinkTarget() throws Exception { + final ObjectId targetID = repo.blob("target"); + RevCommit c = + repo.parseBody( + repo.branch("master") + .commit() + .edit( + new PathEdit("link") { + @Override + public void apply(DirCacheEntry ent) { + ent.setFileMode(FileMode.SYMLINK); + ent.setObjectId(targetID); + } + }) + .create()); + + Tree tree = buildJson(Tree.class, "/repo/+/master/", "long=1"); + + assertThat(tree.id).isEqualTo(c.getTree().name()); + assertThat(tree.entries).hasSize(1); + + TreeJsonData.Entry e = tree.entries.get(0); + assertThat(e.mode).isEqualTo(0120000); + assertThat(e.type).isEqualTo("blob"); + assertThat(e.name).isEqualTo("link"); + assertThat(e.id).isEqualTo(targetID.name()); + assertThat(e.target).isEqualTo("target"); + } + + @Test public void treeJson() throws Exception { RevCommit c = repo.parseBody(