Add text support for tree paths
Match the output of git ls-tree, base64-encoded.
Change-Id: I5a949e69920dbc942f3f12e690213dfc3bdeaf9a
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 bcbb1a5..1ba2477 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/PathServlet.java
@@ -50,6 +50,7 @@
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.QuotedString;
import org.eclipse.jgit.util.RawParseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -173,19 +174,18 @@
return;
}
+ // Write base64 as plain text without modifying any other headers, under
+ // the assumption that any hint we can give to a browser that this is
+ // base64 data might cause it to try to decode it and render as HTML,
+ // which would be bad.
switch (wr.type) {
case SYMLINK:
case REGULAR_FILE:
case EXECUTABLE_FILE:
- // Write base64 as plain text without modifying any other headers,
- // under the assumption that any hint we can give to a browser that
- // this is base64 data might cause it to try to decode it and render
- // as HTML, which would be bad.
- res.setHeader(MODE_HEADER, String.format("%06o", wr.type.mode.getBits()));
- try (Writer writer = startRenderText(req, res, null);
- OutputStream out = BaseEncoding.base64().encodingStream(writer)) {
- rw.getObjectReader().open(wr.id).copyTo(out);
- }
+ writeBlobText(req, res, wr);
+ break;
+ case TREE:
+ writeTreeText(req, res, wr);
break;
default:
renderTextError(req, res, SC_NOT_FOUND, "Not a file");
@@ -201,6 +201,40 @@
}
}
+ private void setModeHeader(HttpServletResponse res, FileType type) {
+ res.setHeader(MODE_HEADER, String.format("%06o", type.mode.getBits()));
+ }
+
+ private void writeBlobText(HttpServletRequest req, HttpServletResponse res, WalkResult wr)
+ throws IOException {
+ setModeHeader(res, wr.type);
+ try (Writer writer = startRenderText(req, res, null);
+ OutputStream out = BaseEncoding.base64().encodingStream(writer)) {
+ wr.getObjectReader().open(wr.id).copyTo(out);
+ }
+ }
+
+ private void writeTreeText(HttpServletRequest req, HttpServletResponse res, WalkResult wr)
+ throws IOException {
+ setModeHeader(res, wr.type);
+
+ try (Writer writer = startRenderText(req, res, null);
+ OutputStream out = BaseEncoding.base64().encodingStream(writer)) {
+ // Match git ls-tree format.
+ while (wr.tw.next()) {
+ FileMode mode = wr.tw.getFileMode(0);
+ out.write(Constants.encode(String.format("%06o", mode.getBits())));
+ out.write(' ');
+ out.write(Constants.encode(Constants.typeString(mode.getObjectType())));
+ out.write(' ');
+ wr.tw.getObjectId(0).copyTo(out);
+ out.write('\t');
+ out.write(Constants.encode(QuotedString.GIT_PATH.quote(wr.tw.getNameString())));
+ out.write('\n');
+ }
+ }
+ }
+
private static RevTree getRoot(GitilesView view, RevWalk rw) throws IOException {
RevObject obj = rw.peel(rw.parseAny(view.getRevision().getId()));
switch (obj.getType()) {
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 a6d29b6..02d7463 100644
--- a/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java
+++ b/gitiles-servlet/src/test/java/com/google/gitiles/PathServletTest.java
@@ -33,6 +33,7 @@
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevTree;
import org.junit.Before;
import org.junit.Test;
@@ -161,7 +162,7 @@
public void blobText() throws Exception {
repo.branch("master").commit().add("foo", "contents").create();
String text = buildText("/repo/+/master/foo?format=TEXT", "100644");
- assertEquals("contents", new String(BaseEncoding.base64().decode(text), UTF_8));
+ assertEquals("contents", decodeBase64(text));
}
@Test
@@ -176,7 +177,30 @@
}
}).create();
String text = buildText("/repo/+/master/baz?format=TEXT", "120000");
- assertEquals("foo", new String(BaseEncoding.base64().decode(text), UTF_8));
+ assertEquals("foo", decodeBase64(text));
+ }
+
+ @Test
+ public void treeText() throws Exception {
+ RevBlob blob = repo.blob("contents");
+ RevTree tree = repo.tree(repo.file("foo/bar", blob));
+ repo.branch("master").commit().setTopLevelTree(tree).create();
+
+ String expected = "040000 tree " + repo.get(tree, "foo").name() + "\tfoo\n";
+ assertEquals(expected, decodeBase64(buildText("/repo/+/master/?format=TEXT", "040000")));
+
+ expected = "100644 blob " + blob.name() + "\tbar\n";
+ assertEquals(expected, decodeBase64(buildText("/repo/+/master/foo?format=TEXT", "040000")));
+ assertEquals(expected, decodeBase64(buildText("/repo/+/master/foo/?format=TEXT", "040000")));
+ }
+
+ @Test
+ public void treeTextEscaped() throws Exception {
+ RevBlob blob = repo.blob("contents");
+ repo.branch("master").commit().add("foo\nbar\rbaz", blob).create();
+
+ assertEquals("100644 blob " + blob.name() + "\t\"foo\\nbar\\rbaz\"\n",
+ decodeBase64(buildText("/repo/+/master/?format=TEXT", "040000")));
}
@Test
@@ -197,9 +221,6 @@
}).create();
assertNotFound("/repo/+/master/nonexistent?format=TEXT");
- assertNotFound("/repo/+/master/?format=TEXT");
- assertNotFound("/repo/+/master/foo?format=TEXT");
- assertNotFound("/repo/+/master/foo/?format=TEXT");
assertNotFound("/repo/+/master/gitiles?format=TEXT");
}
@@ -235,4 +256,8 @@
// the Soy data for introspection.
return BaseServlet.getData(service(pathAndQuery).getRequest());
}
+
+ private static String decodeBase64(String in) {
+ return new String(BaseEncoding.base64().decode(in), UTF_8);
+ }
}