Render custom templates using deltemplate with variants

This new feature in Soy[1] allows dynamically choosing a variant
template at runtime. Use this in conjunction with reading the config
for a particular request to allow per-request (e.g. per-repo)
templates. Currently only supports the customHeader template, which
uses template.customHeader to specify the variant name.
(Unfortunately like most stuff that is common to all pages, we need
to pass this around manually.)

Since we no longer need to exclude the default custom templates, we
can delete DefaultCustomTemplates.soy.

[1] https://developers.google.com/closure/templates/docs/commands#delegates-with-variant

Change-Id: I4f5d33e6e49b5c6af640f4ed6138b018a11745ae
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/BaseServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/BaseServlet.java
index ba0ee5c..76d9f96 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/BaseServlet.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/BaseServlet.java
@@ -194,6 +194,12 @@
       setCacheHeaders(res);
 
       Map<String, Object> allData = getData(req);
+
+      String headerVariant = getAccess(req).getConfig().getString("template", null, "customHeader");
+      if (headerVariant != null) {
+        allData.put("headerVariant", headerVariant);
+      }
+
       allData.putAll(soyData);
       GitilesView view = ViewFilter.getView(req);
       if (!allData.containsKey("repositoryName") && view.getRepositoryName() != null) {
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/DebugRenderer.java b/gitiles-servlet/src/main/java/com/google/gitiles/DebugRenderer.java
index 366191a..9638fd8 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/DebugRenderer.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/DebugRenderer.java
@@ -16,7 +16,7 @@
 
 import static com.google.common.base.Preconditions.checkState;
 
-import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableMap;
 import com.google.template.soy.SoyFileSet;
 import com.google.template.soy.tofu.SoyTofu;
@@ -27,17 +27,13 @@
 
 /** Renderer that reloads Soy templates from the filesystem on every request. */
 public class DebugRenderer extends Renderer {
-  public DebugRenderer(String staticPrefix, String customTemplatesFilename,
+  public DebugRenderer(String staticPrefix, Iterable<String> customTemplatesFilenames,
       final String soyTemplatesRoot, String siteTitle) {
     super(
-        new Function<String, URL>() {
-          @Override
-          public URL apply(String name) {
-            return toFileURL(soyTemplatesRoot + File.separator + name);
-          }
-        },
+        new FileUrlMapper(soyTemplatesRoot + File.separator),
         ImmutableMap.<String, String> of(), staticPrefix,
-        toFileURL(customTemplatesFilename), siteTitle);
+        FluentIterable.from(customTemplatesFilenames).transform(new FileUrlMapper()),
+        siteTitle);
   }
 
   @Override
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/DefaultRenderer.java b/gitiles-servlet/src/main/java/com/google/gitiles/DefaultRenderer.java
index e2eef7c..0741fc2 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/DefaultRenderer.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/DefaultRenderer.java
@@ -31,12 +31,12 @@
     this("", null, "");
   }
 
-  public DefaultRenderer(String staticPrefix, URL customTemplates, String siteTitle) {
+  public DefaultRenderer(String staticPrefix, Iterable<URL> customTemplates, String siteTitle) {
     this(ImmutableMap.<String, String> of(), staticPrefix, customTemplates, siteTitle);
   }
 
-  public DefaultRenderer(Map<String, String> globals, String staticPrefix, URL customTemplates,
-      String siteTitle) {
+  public DefaultRenderer(Map<String, String> globals, String staticPrefix,
+      Iterable<URL> customTemplates, String siteTitle) {
     super(
         new Function<String, URL>() {
           @Override
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java b/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java
index e8b161d..b878415 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java
@@ -21,10 +21,12 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Maps;
+import com.google.gitiles.Renderer.FileUrlMapper;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -42,6 +44,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.regex.Pattern;
@@ -322,7 +325,9 @@
     if (renderer == null) {
       renderer = new DefaultRenderer(
           filterConfig.getServletContext().getContextPath() + STATIC_PREFIX,
-          Renderer.toFileURL(config.getString("gitiles", null, "customTemplates")),
+          FluentIterable.from(Arrays.asList(
+                config.getStringList("gitiles", null, "customTemplates")))
+              .transform(new FileUrlMapper()),
           Objects.firstNonNull(config.getString("gitiles", null, "siteTitle"), "Gitiles"));
     }
   }
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/Renderer.java b/gitiles-servlet/src/main/java/com/google/gitiles/Renderer.java
index 1ab26c4..643c389 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/Renderer.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/Renderer.java
@@ -18,9 +18,10 @@
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.template.soy.tofu.SoyTofu;
 
@@ -52,14 +53,27 @@
       "gitiles.PRETTIFY_CSS_URL", "prettify/prettify.css",
       "gitiles.PRETTIFY_JS_URL", "prettify/prettify.js");
 
-  protected static final URL toFileURL(String filename) {
-    if (filename == null) {
-      return null;
+  protected static class FileUrlMapper implements Function<String, URL> {
+    private final String prefix;
+
+    protected FileUrlMapper() {
+      this("");
     }
-    try {
-      return new File(filename).toURI().toURL();
-    } catch (MalformedURLException e) {
-      throw new IllegalArgumentException(e);
+
+    protected FileUrlMapper(String prefix) {
+      this.prefix = checkNotNull(prefix, "prefix");
+    }
+
+    @Override
+    public URL apply(String filename) {
+      if (filename == null) {
+        return null;
+      }
+      try {
+        return new File(prefix + filename).toURI().toURL();
+      } catch (MalformedURLException e) {
+        throw new IllegalArgumentException(e);
+      }
     }
   }
 
@@ -67,18 +81,10 @@
   protected ImmutableMap<String, String> globals;
 
   protected Renderer(Function<String, URL> resourceMapper, Map<String, String> globals,
-      String staticPrefix, URL customTemplates, String siteTitle) {
+      String staticPrefix, Iterable<URL> customTemplates, String siteTitle) {
     checkNotNull(staticPrefix, "staticPrefix");
-    List<URL> allTemplates = Lists.newArrayListWithCapacity(SOY_FILENAMES.size() + 1);
-    for (String filename : SOY_FILENAMES) {
-      allTemplates.add(resourceMapper.apply(filename));
-    }
-    if (customTemplates != null) {
-      allTemplates.add(customTemplates);
-    } else {
-      allTemplates.add(resourceMapper.apply("DefaultCustomTemplates.soy"));
-    }
-    templates = ImmutableList.copyOf(allTemplates);
+    Iterable<URL> allTemplates = FluentIterable.from(SOY_FILENAMES).transform(resourceMapper);
+    templates = ImmutableList.copyOf(Iterables.concat(allTemplates, customTemplates));
 
     Map<String, String> allGlobals = Maps.newHashMap();
     for (Map.Entry<String, String> e : STATIC_URL_GLOBALS.entrySet()) {