Add Sub Navbar Support To Gitiles

This change allows subdirectories to specify their own navbars
only when the subnavbar markdown config is specified.

Resolves #148.

Change-Id: I2013bf5798a098f0340e3cf6a0ee91286432edc0
diff --git a/java/com/google/gitiles/doc/DocServlet.java b/java/com/google/gitiles/doc/DocServlet.java
index 1a4fce9..61adfe2 100644
--- a/java/com/google/gitiles/doc/DocServlet.java
+++ b/java/com/google/gitiles/doc/DocServlet.java
@@ -109,7 +109,7 @@
         return;
       }
 
-      MarkdownFile navmd = findFile(rw, root, NAVBAR_MD);
+      MarkdownFile navmd = findNavbar(rw, root, path);
       String curEtag = etag(srcmd, navmd);
       if (etagMatch(req, curEtag)) {
         res.setStatus(SC_NOT_MODIFIED);
@@ -167,6 +167,26 @@
     return h.hash().toString();
   }
 
+  private MarkdownFile findNavbar(RevWalk rw, RevTree root, String path)
+      throws IOException {
+    if (!Strings.isNullOrEmpty(path)) {
+      // Traverse up the path until we find a NAVBAR_MD.
+      StringBuilder pathRemaining = new StringBuilder(path);
+      while (pathRemaining.length() > 0) {
+        int lastPathSeparatorIndex = pathRemaining.lastIndexOf("/");
+        pathRemaining.setLength(lastPathSeparatorIndex + 1);
+        MarkdownFile navmd = findFile(rw, root, pathRemaining.toString() + NAVBAR_MD);
+        if (navmd != null) {
+          return navmd;
+        }
+        pathRemaining.setLength(Math.max(lastPathSeparatorIndex, 0));
+      }
+      return null;
+    }
+
+    return findFile(rw, root, NAVBAR_MD);
+  }
+
   private void showDoc(
       HttpServletRequest req,
       HttpServletResponse res,
diff --git a/javatests/com/google/gitiles/doc/DocServletTest.java b/javatests/com/google/gitiles/doc/DocServletTest.java
index c27f0ba..782fc5c 100644
--- a/javatests/com/google/gitiles/doc/DocServletTest.java
+++ b/javatests/com/google/gitiles/doc/DocServletTest.java
@@ -58,6 +58,48 @@
   }
 
   @Test
+  public void simpleSubNavbar() throws Exception {
+    String rootNavbar =
+        "# Site Title\n\n* [Home](index.md)\n* [README](README.md)\n";
+    String subNavbar =
+        "# Subdir Title\n\n* [Sub Home](index.md)\n* [Sub README](README.md)\n";
+    repo.branch("master")
+        .commit()
+        .add("README.md", "# page\n\nof information.")
+        .add("navbar.md", rootNavbar)
+        .add("subdir/README.md", "# subdir page\n\nof information.")
+        .add("subdir/navbar.md", subNavbar)
+        .create();
+
+    String rootReadmeHtml = buildHtml("/repo/+doc/master/README.md");
+    assertThat(rootReadmeHtml).contains("<title>Site Title - page</title>");
+
+    assertThat(rootReadmeHtml).contains("<span class=\"Header-anchorTitle\">Site Title</span>");
+    assertThat(rootReadmeHtml).contains("<li><a href=\"/b/repo/+/master/index.md\">Home</a></li>");
+    assertThat(rootReadmeHtml)
+        .contains("<li><a href=\"/b/repo/+/master/README.md\">README</a></li>");
+    assertThat(rootReadmeHtml)
+        .contains("<h1><a class=\"h\" name=\"page\" href=\"#page\"><span></span></a>page</h1>");
+
+    String subdirReadmeHtml = buildHtml("/repo/+doc/master/subdir/README.md");
+    assertThat(subdirReadmeHtml).contains("<title>Subdir Title - subdir page</title>");
+
+    assertThat(subdirReadmeHtml).contains("<span class=\"Header-anchorTitle\">Subdir Title</span>");
+    assertThat(subdirReadmeHtml)
+        .contains("<li><a href=\"/b/repo/+/master/subdir/index.md\">Sub Home</a></li>");
+    assertThat(subdirReadmeHtml)
+        .contains("<li><a href=\"/b/repo/+/master/subdir/README.md\">Sub README</a></li>");
+    assertThat(subdirReadmeHtml)
+        .contains(
+            "<h1><a class=\"h\" name=\"subdir-page\" href=\"#subdir-page\"><span></span>"
+                + "</a>subdir page</h1>");
+    assertThat(subdirReadmeHtml)
+        .doesNotContain("<li><a href=\"/b/repo/+/master/index.md\">Home</a></li>");
+    assertThat(subdirReadmeHtml)
+        .doesNotContain("<li><a href=\"/b/repo/+/master/README.md\">README</a></li>");
+  }
+
+  @Test
   public void dropsHtml() throws Exception {
     String markdown =
         "# B. Ad\n"