Merge "Clean up old Maven to Buck switch criteria"
diff --git a/Documentation/BUCK b/Documentation/BUCK
index b1a8220..faa2553 100644
--- a/Documentation/BUCK
+++ b/Documentation/BUCK
@@ -20,23 +20,32 @@
       'images/*.jpg',
       'images/*.png',
     ]) + [
+    genfile('doc.css'),
     genfile('licenses.html'),
     genfile('licenses.txt'),
   ],
   deps = [':' + d for d in HTML] + [
     ':licenses.html',
     ':licenses.txt',
+    ':doc.css',
   ],
   out = 'html.zip',
   visibility = ['PUBLIC'],
 )
 
+genrule(
+  name = 'doc.css',
+  cmd = 'ln -s $SRCDIR/doc.css $OUT',
+  srcs = ['doc.css'],
+  out = 'doc.css',
+)
+
 genasciidoc(
   srcs = SRCS + [genfile('licenses.txt')],
   outs = HTML + ['licenses.html'],
   deps = DOCUMENTATION_DEPS,
   attributes = documentation_attributes(git_describe()),
-  backend = 'xhtml11',
+  backend = 'html5',
 )
 
 genrule(
diff --git a/Documentation/asciidoc.defs b/Documentation/asciidoc.defs
index 694d6b5..8279847 100644
--- a/Documentation/asciidoc.defs
+++ b/Documentation/asciidoc.defs
@@ -21,7 +21,7 @@
     visibility = []):
   EXPN = '.expn'
 
-  asciidoc = ['asciidoc']
+  asciidoc = ['$(exe //lib/asciidoctor:asciidoc)']
   if backend:
     asciidoc.extend(['-b', backend])
   for attribute in attributes:
@@ -52,7 +52,10 @@
       name = out,
       cmd = ' '.join(asciidoc + ['$SRCDIR/' + ex]),
       srcs = [genfile(ex)] + [genfile(n + EXPN) for n in dep],
-      deps = [':' + ex] + [':' + n + EXPN for n in dep],
+      deps = [':' + n + EXPN for n in dep] + [
+        ':' + ex,
+        '//lib/asciidoctor:asciidoc',
+      ],
       out = out,
       visibility = visibility,
     )
diff --git a/Documentation/config.defs b/Documentation/config.defs
index af5c729..28dd2c8 100644
--- a/Documentation/config.defs
+++ b/Documentation/config.defs
@@ -13,5 +13,7 @@
     'startsb="["',
     'endsb="]"',
     'tilde="~"',
-    'revision="%s"' % revision,
+    'source-highlighter=prettify',
+    'stylesheet=doc.css',
+    'revnumber="%s"' % revision,
   ]
diff --git a/Documentation/dev-buck.txt b/Documentation/dev-buck.txt
index 03bf74c..7671767 100644
--- a/Documentation/dev-buck.txt
+++ b/Documentation/dev-buck.txt
@@ -178,6 +178,42 @@
 is not regenerated.
 
 
+[[documentation]]
+Documentation
+~~~~~~~~~~~~~
+
+To build the documentation:
+
+----
+  buck build docs
+----
+
+The generated html files will be placed in:
+
+----
+  buck-out/gen/Documentation
+----
+
+The html files will also be bundled into `html.zip` in the same location.
+
+
+[[release]]
+Gerrit Release WAR File
+~~~~~~~~~~~~~~~~~~~~~~~
+
+To build the release of the Gerrit web application, including documentation and
+all core plugins:
+
+----
+  buck build release
+----
+
+The output release WAR will be placed in:
+
+----
+  buck-out/gen/release.war
+----
+
 [[tests]]
 Running Unit Tests
 ------------------
diff --git a/Documentation/doc.css b/Documentation/doc.css
new file mode 100644
index 0000000..3e226fe
--- /dev/null
+++ b/Documentation/doc.css
@@ -0,0 +1,37 @@
+body {
+  margin: 1em;
+}
+
+#toctitle {
+  margin-top: 0.5em;
+  font-weight: bold;
+}
+
+h1, h2, h3, h4, h5, h6, #toctitle {
+  color: #527bbd;
+  font-family: sans-serif;
+}
+
+h1, h2, h3 {
+  border-bottom: 2px solid silver;
+}
+
+p {
+  margin: 0.5em 0 0.5em 0;
+}
+li p {
+  margin: 0.2em 0 0.2em 0;
+}
+
+pre {
+  border: 2px solid silver;
+  background: #ebebeb;
+  margin-left: 2em;
+  width: 100em;
+  color: darkgreen;
+  padding: 2px;
+}
+
+dl dt {
+  margin-top: 1em;
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
index 970b317..09aef22 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
@@ -216,7 +216,7 @@
         Gerrit.displayLastChangeList();
       }
     });
-    keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReload()) {
+    keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReloadChange()) {
       @Override
       public void onKeyPress(final KeyPressEvent event) {
         reload.reload();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
index 2580542..6273717 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
@@ -21,6 +21,8 @@
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gwt.core.client.JsArray;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwtexpui.globalkey.client.KeyCommand;
 
 import java.util.Collections;
 import java.util.Comparator;
@@ -41,7 +43,16 @@
   @Override
   protected void onInitUI() {
     super.onInitUI();
-    table = new ChangeTable2();
+    table = new ChangeTable2() {
+      {
+        keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReloadSearch()) {
+          @Override
+          public void onKeyPress(final KeyPressEvent event) {
+            Gerrit.display(getToken());
+          }
+        });
+      }
+    };
     table.addStyleName(Gerrit.RESOURCES.css().accountDashboard());
 
     outgoing = new ChangeTable2.Section();
@@ -63,6 +74,7 @@
   @Override
   protected void onLoad() {
     super.onLoad();
+
     String who = mine ? "self" : ownerId.toString();
     ChangeList.query(
         new ScreenLoadCallback<JsArray<ChangeList>>(this) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
index 81d4cc3..197b466 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
@@ -56,7 +56,8 @@
   String expandCollapseDependencies();
   String previousPatchSet();
   String nextPatchSet();
-  String keyReload();
+  String keyReloadChange();
+  String keyReloadSearch();
   String keyPublishComments();
   String keyEditTopic();
   String keyEditMessage();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
index 7bc6eb1..f51cff0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
@@ -36,7 +36,8 @@
 expandCollapseDependencies = Expands / Collapses dependencies section
 previousPatchSet = Previous patch set
 nextPatchSet = Next patch set
-keyReload = Reload change
+keyReloadChange = Reload change
+keyReloadSearch = Reload change list
 keyPublishComments = Review and publish comments
 keyEditTopic = Edit change topic
 keyEditMessage = Edit commit message
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
index 2310bf8..b2ccbcb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
@@ -76,6 +76,13 @@
             .changeTablePagePrev(), prev));
         keysNavigation.add(new DoLinkCommand(0, ']', Util.C
             .changeTablePageNext(), next));
+
+        keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReloadSearch()) {
+          @Override
+          public void onKeyPress(final KeyPressEvent event) {
+            Gerrit.display(getToken());
+          }
+        });
       }
     };
     section = new ChangeTable2.Section();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
index c5e2739..e9704e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
@@ -189,18 +189,18 @@
 
     m.setBase(originalCommit.getParent(0));
     if (m.merge(mergeTip, originalCommit)) {
+      ObjectId tree = m.getResultTreeId();
+      if (tree.equals(mergeTip.getTree())) {
+        return null;
+      }
 
-      final CommitBuilder mergeCommit = new CommitBuilder();
-
-      mergeCommit.setTreeId(m.getResultTreeId());
+      CommitBuilder mergeCommit = new CommitBuilder();
+      mergeCommit.setTreeId(tree);
       mergeCommit.setParentId(mergeTip);
       mergeCommit.setAuthor(originalCommit.getAuthorIdent());
       mergeCommit.setCommitter(cherryPickCommitterIdent);
       mergeCommit.setMessage(commitMsg);
-
-      final ObjectId id = commit(inserter, mergeCommit);
-
-      return rw.parseCommit(id);
+      return rw.parseCommit(commit(inserter, mergeCommit));
     } else {
       return null;
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
index 483ecaf..6647652 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
@@ -77,7 +77,7 @@
 
       boolean perUser = false;
       Map<AccessSection, Project.NameKey> sectionToProject = Maps.newLinkedHashMap();
-      for (SectionMatcher matcher : matcherList) {
+      for (SectionMatcher sm : matcherList) {
         // If the matcher has to expand parameters and its prefix matches the
         // reference there is a very good chance the reference is actually user
         // specific, even if the matcher does not match the reference. Since its
@@ -91,12 +91,12 @@
         // references are usually less frequent than the non-user references.
         //
         if (username != null && !perUser
-            && matcher instanceof SectionMatcher.ExpandParameters) {
-          perUser = ((SectionMatcher.ExpandParameters) matcher).matchPrefix(ref);
+            && sm.matcher instanceof RefPatternMatcher.ExpandParameters) {
+          perUser = ((RefPatternMatcher.ExpandParameters) sm.matcher).matchPrefix(ref);
         }
 
-        if (matcher.match(ref, username)) {
-          sectionToProject.put(matcher.section, matcher.project);
+        if (sm.match(ref, username)) {
+          sectionToProject.put(sm.section, sm.project);
         }
       }
       List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefPatternMatcher.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefPatternMatcher.java
new file mode 100644
index 0000000..b71d194
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefPatternMatcher.java
@@ -0,0 +1,122 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.project;
+
+import static com.google.gerrit.server.project.RefControl.isRE;
+import com.google.gerrit.common.data.ParameterizedString;
+import dk.brics.automaton.Automaton;
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+abstract class RefPatternMatcher {
+  public static RefPatternMatcher getMatcher(String pattern) {
+    if (pattern.contains("${")) {
+      return new ExpandParameters(pattern);
+    } else if (isRE(pattern)) {
+      return new Regexp(pattern);
+    } else if (pattern.endsWith("/*")) {
+      return new Prefix(pattern.substring(0, pattern.length() - 1));
+    } else {
+      return new Exact(pattern);
+    }
+  }
+
+  abstract boolean match(String ref, String username);
+
+  private static class Exact extends RefPatternMatcher {
+    private final String expect;
+
+    Exact(String name) {
+      expect = name;
+    }
+
+    @Override
+    boolean match(String ref, String username) {
+      return expect.equals(ref);
+    }
+  }
+
+  private static class Prefix extends RefPatternMatcher {
+    private final String prefix;
+
+    Prefix(String pfx) {
+      prefix = pfx;
+    }
+
+    @Override
+    boolean match(String ref, String username) {
+      return ref.startsWith(prefix);
+    }
+  }
+
+  private static class Regexp extends RefPatternMatcher {
+    private final Pattern pattern;
+
+    Regexp(String re) {
+      pattern = Pattern.compile(re);
+    }
+
+    @Override
+    boolean match(String ref, String username) {
+      return pattern.matcher(ref).matches();
+    }
+  }
+
+  static class ExpandParameters extends RefPatternMatcher {
+    private final ParameterizedString template;
+    private final String prefix;
+
+    ExpandParameters(String pattern) {
+      template = new ParameterizedString(pattern);
+
+      if (isRE(pattern)) {
+        // Replace ${username} with ":USERNAME:" as : is not legal
+        // in a reference and the string :USERNAME: is not likely to
+        // be a valid part of the regex. This later allows the pattern
+        // prefix to be clipped, saving time on evaluation.
+        Automaton am =
+            RefControl.toRegExp(
+                template.replace(Collections.singletonMap("username",
+                    ":USERNAME:"))).toAutomaton();
+        String rePrefix = am.getCommonPrefix();
+        prefix = rePrefix.substring(0, rePrefix.indexOf(":USERNAME:"));
+      } else {
+        prefix = pattern.substring(0, pattern.indexOf("${"));
+      }
+    }
+
+    @Override
+    boolean match(String ref, String username) {
+      if (!ref.startsWith(prefix) || username == null) {
+        return false;
+      }
+
+      String u;
+      if (isRE(template.getPattern())) {
+        u = username.replace(".", "\\.");
+      } else {
+        u = username;
+      }
+
+      RefPatternMatcher next =
+          getMatcher(template.replace(Collections.singletonMap("username", u)));
+      return next != null ? next.match(ref, username) : false;
+    }
+
+    boolean matchPrefix(String ref) {
+      return ref.startsWith(prefix);
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java
index 6f8af80..44c8b9a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java
@@ -14,147 +14,38 @@
 
 package com.google.gerrit.server.project;
 
-import static com.google.gerrit.server.project.RefControl.isRE;
-
 import com.google.gerrit.common.data.AccessSection;
-import com.google.gerrit.common.data.ParameterizedString;
 import com.google.gerrit.reviewdb.client.Project;
 
-import dk.brics.automaton.Automaton;
-
-import java.util.Collections;
-import java.util.regex.Pattern;
-
 /**
  * Matches an AccessSection against a reference name.
  * <p>
  * These matchers are "compiled" versions of the AccessSection name, supporting
  * faster selection of which sections are relevant to any given input reference.
  */
-abstract class SectionMatcher {
+class SectionMatcher extends RefPatternMatcher {
   static SectionMatcher wrap(Project.NameKey project, AccessSection section) {
     String ref = section.getName();
     if (AccessSection.isValid(ref)) {
-      return wrap(project, ref, section);
+      return new SectionMatcher(project, section, getMatcher(ref));
     } else {
       return null;
     }
   }
 
-  static SectionMatcher wrap(Project.NameKey project, String pattern,
-      AccessSection section) {
-    if (pattern.contains("${")) {
-      return new ExpandParameters(project, pattern, section);
-
-    } else if (isRE(pattern)) {
-      return new Regexp(project, pattern, section);
-
-    } else if (pattern.endsWith("/*")) {
-      return new Prefix(project, pattern.substring(0, pattern.length() - 1),
-          section);
-
-    } else {
-      return new Exact(project, pattern, section);
-    }
-  }
-
   final Project.NameKey project;
   final AccessSection section;
+  final RefPatternMatcher matcher;
 
-  SectionMatcher(Project.NameKey project, AccessSection section) {
+  SectionMatcher(Project.NameKey project, AccessSection section,
+      RefPatternMatcher matcher) {
     this.project = project;
     this.section = section;
+    this.matcher = matcher;
   }
 
-  abstract boolean match(String ref, String username);
-
-  private static class Exact extends SectionMatcher {
-    private final String expect;
-
-    Exact(Project.NameKey project, String name, AccessSection section) {
-      super(project, section);
-      expect = name;
-    }
-
-    @Override
-    boolean match(String ref, String username) {
-      return expect.equals(ref);
-    }
-  }
-
-  private static class Prefix extends SectionMatcher {
-    private final String prefix;
-
-    Prefix(Project.NameKey project, String pfx, AccessSection section) {
-      super(project, section);
-      prefix = pfx;
-    }
-
-    @Override
-    boolean match(String ref, String username) {
-      return ref.startsWith(prefix);
-    }
-  }
-
-  private static class Regexp extends SectionMatcher {
-    private final Pattern pattern;
-
-    Regexp(Project.NameKey project, String re, AccessSection section) {
-      super(project, section);
-      pattern = Pattern.compile(re);
-    }
-
-    @Override
-    boolean match(String ref, String username) {
-      return pattern.matcher(ref).matches();
-    }
-  }
-
-  static class ExpandParameters extends SectionMatcher {
-    private final ParameterizedString template;
-    private final String prefix;
-
-    ExpandParameters(Project.NameKey project, String pattern,
-        AccessSection section) {
-      super(project, section);
-      template = new ParameterizedString(pattern);
-
-      if (isRE(pattern)) {
-        // Replace ${username} with ":USERNAME:" as : is not legal
-        // in a reference and the string :USERNAME: is not likely to
-        // be a valid part of the regex. This later allows the pattern
-        // prefix to be clipped, saving time on evaluation.
-        Automaton am = RefControl.toRegExp(
-            template.replace(Collections.singletonMap("username", ":USERNAME:")))
-            .toAutomaton();
-        String rePrefix = am.getCommonPrefix();
-        prefix = rePrefix.substring(0, rePrefix.indexOf(":USERNAME:"));
-      } else {
-        prefix = pattern.substring(0, pattern.indexOf("${"));
-      }
-    }
-
-    @Override
-    boolean match(String ref, String username) {
-      if (!ref.startsWith(prefix) || username == null) {
-        return false;
-      }
-
-      String u;
-      if (isRE(template.getPattern())) {
-        u = username.replace(".", "\\.");
-      } else {
-        u = username;
-      }
-
-      SectionMatcher next = wrap(project,
-          template.replace(Collections.singletonMap("username", u)),
-          section);
-      return next != null ? next.match(ref, username) : false;
-    }
-
-   boolean matchPrefix(String ref) {
-     return ref.startsWith(prefix);
-    }
+  @Override
+  boolean match(String ref, String username) {
+    return this.matcher.match(ref, username);
   }
 }
diff --git a/lib/asciidoctor/BUCK b/lib/asciidoctor/BUCK
new file mode 100644
index 0000000..25b9eb8
--- /dev/null
+++ b/lib/asciidoctor/BUCK
@@ -0,0 +1,39 @@
+include_defs('//lib/maven.defs')
+
+java_binary(
+  name = 'asciidoc',
+  main_class = 'org.asciidoctor.cli.AsciidoctorInvoker',
+  deps = [':asciidoctor'],
+  visibility = ['PUBLIC'],
+)
+
+maven_jar(
+  name = 'asciidoctor',
+  id = 'org.asciidoctor:asciidoctor-java-integration:0.1.3',
+  sha1 = '5cf21b4331d737ef0f3b3f543a7e5a343c1f27ec',
+  license = 'Apache2.0',
+  visibility = [],
+  attach_source = False,
+  deps = [
+    ':jcommander',
+    ':jruby',
+  ],
+)
+
+maven_jar(
+  name = 'jcommander',
+  id = 'com.beust:jcommander:1.30',
+  sha1 = 'c440b30a944ba199751551aee393f8aa03b3c327',
+  license = 'Apache2.0',
+  visibility = [],
+  attach_source = False,
+)
+
+maven_jar(
+  name = 'jruby',
+  id = 'org.jruby:jruby-complete:1.7.4',
+  sha1 = '74984d84846523bd7da49064679ed1ccf199e1db',
+  license = 'DO_NOT_DISTRIBUTE',
+  visibility = [],
+  attach_source = False,
+)