Merge branch 'stable-2.14' into stable-2.15

* stable-2.14:
  Replace bazel-genfiles with bazel-bin in documentation

Change-Id: I70ea61357ec662fa2e18325a437185d27bcd4f3d
diff --git a/WORKSPACE b/WORKSPACE
index cd782bc..4af3dbf 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "bec81c8319e560d2a92ba0fe35d40d021ffd7708",
+    commit = "ae1cd231b0262b2738e6c0593eb3c504209ad4f5",
     #local_path = "/home/<user>/projects/bazlets",
 )
 
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index c07795a..85c3a37 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -1,21 +1,20 @@
-load("//tools/bzl:maven_jar.bzl", "GERRIT", "maven_jar")
+load("//tools/bzl:maven_jar.bzl", "GERRIT", "MAVEN_CENTRAL", "MAVEN_LOCAL", "maven_jar")
 
-COMMONMARK_VERSION = "0.6.0"
+COMMONMARK_VERSION = "0.10.0"
 
 def external_plugin_deps():
     maven_jar(
         name = "gitiles-servlet",
-        artifact = "com.google.gitiles:gitiles-servlet:0.2-1",
-        sha1 = "4b83471c65e110a08d99570fafcdaf5f59a0b9ce",
+        artifact = "com.google.gitiles:gitiles-servlet:0.2-5",
+        sha1 = "18186bd83a8c52a4a965472fcb9b4ea87862eb35",
         repository = GERRIT,
     )
 
     # prettify must match the version used in Gitiles
     maven_jar(
         name = "prettify",
-        artifact = "prettify:java-prettify:1.2.1",
-        sha1 = "29ad8d072f9d0b83d1a2e9aa6ccb0905e6d543c6",
-        repository = GERRIT,
+        artifact = "com.github.twalcari:java-prettify:1.2.2",
+        sha1 = "b8ba1c1eb8b2e45cfd465d01218c6060e887572e",
     )
 
     maven_jar(
@@ -24,32 +23,33 @@
         sha1 = "557edd918fd41f9260963583ebf5a61a43a6b423",
     )
 
+    # commonmark must match the version used in Gitiles
     maven_jar(
         name = "commonmark",
         artifact = "com.atlassian.commonmark:commonmark:" + COMMONMARK_VERSION,
-        sha1 = "5df3f6fa3073966620685924aa22d08ece7213f2",
+        sha1 = "119cb7bedc3570d9ecb64ec69ab7686b5c20559b",
     )
 
     maven_jar(
         name = "cm-autolink",
         artifact = "com.atlassian.commonmark:commonmark-ext-autolink:" + COMMONMARK_VERSION,
-        sha1 = "4d7e828a4651e2f590b4a059925991be58e62da6",
+        sha1 = "a6056a5efbd68f57d420bc51bbc54b28a5d3c56b",
     )
 
     maven_jar(
         name = "autolink",
-        artifact = "org.nibor.autolink:autolink:0.4.0",
-        sha1 = "764f7b0147a0675d971a34282dce9ec76b8307c9",
+        artifact = "org.nibor.autolink:autolink:0.7.0",
+        sha1 = "649f9f13422cf50c926febe6035662ae25dc89b2",
     )
 
     maven_jar(
         name = "gfm-strikethrough",
         artifact = "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:" + COMMONMARK_VERSION,
-        sha1 = "75a95aaec77810496de41239bcc773adfb13285f",
+        sha1 = "40837da951b421b545edddac57012e15fcc9e63c",
     )
 
     maven_jar(
         name = "gfm-tables",
         artifact = "com.atlassian.commonmark:commonmark-ext-gfm-tables:" + COMMONMARK_VERSION,
-        sha1 = "ae1c701517e8116bc205b561b9b215a53df8abc7",
+        sha1 = "c075db2a3301100cf70c7dced8ecf86b494458a2",
     )
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitiles/FilteredRepository.java b/src/main/java/com/googlesource/gerrit/plugins/gitiles/FilteredRepository.java
index de023e0..039f78f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/FilteredRepository.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/FilteredRepository.java
@@ -17,16 +17,17 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.SearchingChangeCacheImpl;
-import com.google.gerrit.server.git.TagCache;
 import com.google.gerrit.server.git.VisibleRefFilter;
-import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
 import com.google.gerrit.server.project.NoSuchProjectException;
-import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import java.io.IOException;
@@ -45,56 +46,67 @@
 
 class FilteredRepository extends Repository {
   static class Factory {
-    private final Provider<ReviewDb> db;
-    private final ProjectControl.GenericFactory projectControlFactory;
     private final Provider<CurrentUser> userProvider;
+    private final ProjectCache projectCache;
     private final GitRepositoryManager repoManager;
-    private final TagCache tagCache;
-    private final ChangeNotes.Factory changeNotesFactory;
-    private final SearchingChangeCacheImpl changeCache;
+    private final VisibleRefFilter.Factory visibleRefFilterFactory;
+    private final PermissionBackend permissionBackend;
 
     @Inject
     Factory(
-        Provider<ReviewDb> db,
-        ProjectControl.GenericFactory projectControlFactory,
+        ProjectCache projectCache,
         Provider<CurrentUser> userProvider,
         GitRepositoryManager repoManager,
-        TagCache tagCache,
-        ChangeNotes.Factory changeNotesFactory,
-        SearchingChangeCacheImpl changeCache) {
-      this.db = db;
-      this.projectControlFactory = projectControlFactory;
+        VisibleRefFilter.Factory visibleRefFilterFactory,
+        PermissionBackend permissionBackend) {
       this.userProvider = userProvider;
+      this.projectCache = projectCache;
       this.repoManager = repoManager;
-      this.tagCache = tagCache;
-      this.changeNotesFactory = changeNotesFactory;
-      this.changeCache = changeCache;
+      this.visibleRefFilterFactory = visibleRefFilterFactory;
+      this.permissionBackend = permissionBackend;
     }
 
-    FilteredRepository create(Project.NameKey name) throws NoSuchProjectException, IOException {
-      ProjectControl ctl = projectControlFactory.controlFor(name, userProvider.get());
-      if (!ctl.isVisible()) {
+    FilteredRepository create(Project.NameKey name)
+        throws NoSuchProjectException, IOException, PermissionBackendException {
+      ProjectState projectState = projectCache.checkedGet(name);
+      if (projectState == null || !projectState.getProject().getState().permitsRead()) {
         throw new NoSuchProjectException(name);
       }
-      Repository repo = repoManager.openRepository(name);
       return new FilteredRepository(
-          ctl,
-          repo,
-          new VisibleRefFilter(
-              tagCache, changeNotesFactory, changeCache, repo, ctl, db.get(), true));
+          projectState,
+          userProvider.get(),
+          repoManager.openRepository(name),
+          visibleRefFilterFactory,
+          permissionBackend);
     }
   }
 
   private final Repository delegate;
   private final RefDatabase refdb;
 
-  private FilteredRepository(ProjectControl ctl, Repository delegate, VisibleRefFilter refFilter) {
+  private FilteredRepository(
+      ProjectState projectState,
+      CurrentUser user,
+      Repository delegate,
+      VisibleRefFilter.Factory refFilterFactory,
+      PermissionBackend permissionBackend)
+      throws PermissionBackendException {
     super(toBuilder(delegate));
     this.delegate = delegate;
-    if (ctl.allRefsAreVisible()) {
+    boolean visible = true;
+    try {
+      permissionBackend.user(user).project(projectState.getNameKey()).check(ProjectPermission.READ);
+    } catch (AuthException e) {
+      visible = false;
+    }
+
+    if (visible) {
       this.refdb = delegate.getRefDatabase();
     } else {
-      this.refdb = new FilteredRefDatabase(delegate.getRefDatabase(), refFilter);
+
+      this.refdb =
+          new FilteredRefDatabase(
+              delegate.getRefDatabase(), refFilterFactory.create(projectState, delegate));
     }
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java b/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
index 4e7e612..3b5550a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
@@ -22,6 +22,8 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.AnonymousCowardName;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ListProjects;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectJson;
@@ -31,15 +33,19 @@
 import com.google.gitiles.RepositoryDescription;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import java.io.File;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
+import org.eclipse.jgit.util.FS;
 
 class GerritGitilesAccess implements GitilesAccess {
   // Assisted injection doesn't work with the overridden method, so write the
@@ -49,6 +55,7 @@
     private final ProjectJson projectJson;
     private final Provider<ListProjects> listProjects;
     private final GitilesUrls urls;
+    private final SitePaths site;
     private final Provider<CurrentUser> userProvider;
     private final String anonymousCowardName;
 
@@ -58,12 +65,14 @@
         ProjectJson projectJson,
         Provider<ListProjects> listProjects,
         GitilesUrls urls,
+        SitePaths site,
         Provider<CurrentUser> userProvider,
         @AnonymousCowardName String anonymousCowardName) {
       this.projectCache = projectCache;
       this.projectJson = projectJson;
       this.listProjects = listProjects;
       this.urls = urls;
+      this.site = site;
       this.userProvider = userProvider;
       this.anonymousCowardName = anonymousCowardName;
     }
@@ -78,6 +87,7 @@
   private final ProjectJson projectJson;
   private final Provider<ListProjects> listProjects;
   private final GitilesUrls urls;
+  private final SitePaths site;
   private final Provider<CurrentUser> userProvider;
   private final String anonymousCowardName;
   private final HttpServletRequest req;
@@ -88,6 +98,7 @@
     this.projectJson = factory.projectJson;
     this.listProjects = factory.listProjects;
     this.urls = factory.urls;
+    this.site = factory.site;
     this.userProvider = factory.userProvider;
     this.anonymousCowardName = factory.anonymousCowardName;
     this.req = req;
@@ -106,7 +117,7 @@
     Map<String, ProjectInfo> projects;
     try {
       projects = lp.apply();
-    } catch (BadRequestException e) {
+    } catch (BadRequestException | PermissionBackendException e) {
       throw new IOException(e);
     }
     Map<String, RepositoryDescription> result = Maps.newLinkedHashMap();
@@ -127,6 +138,20 @@
     return desc;
   }
 
+  private Config getGlobalConfig() throws IOException {
+    File cfgFile = site.etc_dir.resolve("gitiles.config").toFile();
+    FileBasedConfig cfg = new FileBasedConfig(cfgFile, FS.DETECTED);
+    try {
+      if (cfg.getFile().exists()) {
+        cfg.load();
+      }
+    } catch (ConfigInvalidException e) {
+      throw new IOException(e);
+    }
+
+    return cfg;
+  }
+
   @Override
   public Object getUserKey() {
     CurrentUser user = userProvider.get();
@@ -155,20 +180,22 @@
   public Config getConfig() throws IOException {
     // Try to get a gitiles.config file from the refs/meta/config branch
     // of the project. For non-project access, use All-Projects as project.
+    // If none of the above exists, use global gitiles.config.
     Project.NameKey nameKey = Resolver.getNameKey(req);
     ProjectState state = projectCache.get(nameKey);
     if (state != null) {
       Config cfg = state.getConfig("gitiles.config").getWithInheritance();
-      if (cfg != null) {
+      if (cfg != null && cfg.getSections().size() > 0) {
         return cfg;
       }
     } else {
       state = projectCache.getAllProjects();
       Config cfg = state.getConfig("gitiles.config").get();
-      if (cfg != null) {
+      if (cfg != null && cfg.getSections().size() > 0) {
         return cfg;
       }
     }
-    return new Config();
+
+    return getGlobalConfig();
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitiles/Resolver.java b/src/main/java/com/googlesource/gerrit/plugins/gitiles/Resolver.java
index 4b08996..fcdae61 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/Resolver.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/Resolver.java
@@ -18,6 +18,7 @@
 
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -68,7 +69,7 @@
       // Avoid leaking information by not distinguishing between
       // project not existing and no access rights.
       throw new ServiceNotAuthorizedException();
-    } catch (IOException e) {
+    } catch (IOException | PermissionBackendException e) {
       ServiceMayNotContinueException err =
           new ServiceMayNotContinueException("error opening repository " + name);
       err.initCause(e);
diff --git a/tools/bzl/maven_jar.bzl b/tools/bzl/maven_jar.bzl
index 528bffe..fb20419 100644
--- a/tools/bzl/maven_jar.bzl
+++ b/tools/bzl/maven_jar.bzl
@@ -3,8 +3,10 @@
     _gerrit = "GERRIT",
     _maven_central = "MAVEN_CENTRAL",
     _maven_jar = "maven_jar",
+    _maven_local = "MAVEN_LOCAL",
 )
 
 GERRIT = _gerrit
 MAVEN_CENTRAL = _maven_central
+MAVEN_LOCAL = _maven_local
 maven_jar = _maven_jar