Add "pretty" log variants for more flexible log formatting.

Variant views are triggered by passing the 'pretty=FORMAT' URL param, such
as 'pretty=full' or 'pretty=oneline'.

Additional variants or overrides can be declared in gitiles.config with:
  [logFormat "oneline"]
    variant = myOnelineVariantOverride
  [logFormat "special"]
    variant = myCompletelyCustomVariant

Change-Id: If30554995062110bfbf22ee8760db8303d50b69c
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java
index 4d1da1c..ff1fb7b 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/LogServlet.java
@@ -18,6 +18,7 @@
 import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
 
+import com.google.common.base.Objects;
 import com.google.common.base.Optional;
 import com.google.common.base.Strings;
 import com.google.common.collect.Iterables;
@@ -33,6 +34,7 @@
 import org.eclipse.jgit.errors.RevWalkException;
 import org.eclipse.jgit.http.server.ServletUtils;
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectReader;
@@ -63,6 +65,7 @@
 
   static final String LIMIT_PARAM = "n";
   static final String START_PARAM = "s";
+  private static final String PRETTY_PARAM = "pretty";
   private static final int DEFAULT_LIMIT = 100;
   private static final int MAX_LIMIT = 10000;
 
@@ -85,8 +88,16 @@
 
     try {
       GitilesAccess access = getAccess(req);
+      Config config = access.getConfig();
       DateFormatter df = new DateFormatter(access, Format.DEFAULT);
-      Map<String, Object> data = new LogSoyData(req, view).toSoyData(paginator, null, df);
+
+      // Allow the user to select a logView variant with the "pretty" param.
+      String pretty = Iterables.getFirst(view.getParameters().get(PRETTY_PARAM), "default");
+      Map<String, Object> data = new LogSoyData(req, view,
+          config.getBoolean("logFormat", pretty, "verbose", false)).toSoyData(paginator, null, df);
+      String variant = config.getString("logFormat", pretty, "variant");
+      data.put("logEntryPretty", pretty);
+      data.put("logEntryVariant", Objects.firstNonNull(variant, pretty));
 
       if (!view.getRevision().nameIsId()) {
         List<Map<String, Object>> tags = Lists.newArrayListWithExpectedSize(1);
@@ -108,7 +119,6 @@
       }
 
       data.put("title", title);
-      GitilesConfig.putVariant(access.getConfig(), "logEntry", "logEntryVariant", data);
 
       renderHtml(req, res, "gitiles.logDetail", data);
     } catch (RevWalkException e) {
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/LogSoyData.java b/gitiles-servlet/src/main/java/com/google/gitiles/LogSoyData.java
index a4be388..cdfdcf5 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/LogSoyData.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/LogSoyData.java
@@ -27,20 +27,29 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 
 public class LogSoyData {
   private static final ImmutableSet<Field> FIELDS = Sets.immutableEnumSet(Field.ABBREV_SHA,
-      Field.URL, Field.SHORT_MESSAGE, Field.AUTHOR, Field.COMMITTER, Field.BRANCHES, Field.TAGS);
+      Field.SHA, Field.URL, Field.SHORT_MESSAGE, Field.MESSAGE, Field.AUTHOR, Field.COMMITTER,
+      Field.BRANCHES, Field.TAGS);
+  private static final ImmutableSet<Field> VERBOSE_FIELDS = Field.setOf(FIELDS, Field.DIFF_TREE);
 
   private final HttpServletRequest req;
   private final GitilesView view;
+  private final boolean verbose;
 
   public LogSoyData(HttpServletRequest req, GitilesView view) {
+    this(req, view, false);
+  }
+
+  public LogSoyData(HttpServletRequest req, GitilesView view, boolean verbose) {
     this.req = req;
     this.view = view;
+    this.verbose = verbose;
   }
 
   public Map<String, Object> toSoyData(RevWalk walk, int limit, @Nullable String revision,
@@ -54,7 +63,8 @@
 
     List<Map<String, Object>> entries = Lists.newArrayListWithCapacity(paginator.getLimit());
     for (RevCommit c : paginator) {
-      entries.add(new CommitSoyData().toSoyData(req, c, FIELDS, df));
+      Set<Field> fs = verbose ? VERBOSE_FIELDS : FIELDS;
+      entries.add(new CommitSoyData().setRevWalk(paginator.getWalk()).toSoyData(req, c, fs, df));
     }
 
     data.put("entries", entries);