Merge branch 'stable-2.14' into stable-2.15

* stable-2.14:
  Update bazlets to latest revision on stable-2.14
  Upgrade to latest bazlets on stable-2.14
  Use latest bazlets

No-op merge, done using `-s ours`.

Change-Id: Id469d2277b7043c089374662157904d150f88d73
diff --git a/WORKSPACE b/WORKSPACE
index 13d1b15..c572f0c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,18 +3,18 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "21e71dc9abb42f5ac80c51d2df2a374c3414b9d2",
+    commit = "cbddbc2b9571b1d692fb823ba8791ccd60b52421",
     #    local_path = "/home/<user>/projects/bazlets",
 )
 
 #Snapshot Plugin API
-# load(
-#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
-#    "gerrit_api_maven_local",
-# )
+#load(
+#   "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
+#   "gerrit_api_maven_local",
+#)
 
 # Load snapshot Plugin API
-# gerrit_api_maven_local()
+#gerrit_api_maven_local()
 
 # Release Plugin API
 load(
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index 49c4fe0..d18ead2 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -1,49 +1,49 @@
-load("//tools/bzl:maven_jar.bzl", "maven_jar", "GERRIT", "MAVEN_CENTRAL")
+load("//tools/bzl:maven_jar.bzl", "maven_jar", "GERRIT", "MAVEN_CENTRAL", "MAVEN_LOCAL")
 
-COMMONMARK_VERSION = '0.6.0'
+COMMONMARK_VERSION = '0.9.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',
   )
 
+  # commonmark must match the version used in Gitiles
   maven_jar(
     name = 'commonmark',
     artifact = 'com.atlassian.commonmark:commonmark:' + COMMONMARK_VERSION,
-    sha1 = '5df3f6fa3073966620685924aa22d08ece7213f2',
+    sha1 = '4eb11e3f9aaecafc6073b84c15f66376ef8dc5d3',
   )
 
   maven_jar(
     name = 'cm_autolink',
     artifact = 'com.atlassian.commonmark:commonmark-ext-autolink:' + COMMONMARK_VERSION,
-    sha1 = '4d7e828a4651e2f590b4a059925991be58e62da6',
+    sha1 = 'b81d7f0e2bdb987d3f447f3e92756bcdbb5ff537',
   )
 
   maven_jar(
     name = 'autolink',
-    artifact = 'org.nibor.autolink:autolink:0.4.0',
-    sha1 = '764f7b0147a0675d971a34282dce9ec76b8307c9',
+    artifact = 'org.nibor.autolink:autolink:0.6.0',
+    sha1 = '3986d016a14e8c81afeec752f19af29b20e8367b',
   )
 
   maven_jar(
     name = 'gfm_strikethrough',
     artifact = 'com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:' + COMMONMARK_VERSION,
-    sha1 = '75a95aaec77810496de41239bcc773adfb13285f',
+    sha1 = 'd6814aac1a6aaa473c0c3ef0a23bfff8836d1e67',
   )
 
   maven_jar(
     name = 'gfm_tables',
     artifact = 'com.atlassian.commonmark:commonmark-ext-gfm-tables:' + COMMONMARK_VERSION,
-    sha1 = 'ae1c701517e8116bc205b561b9b215a53df8abc7',
+    sha1 = '4c8a93ef905ef8fc35d6379965641a980d67e304',
   )
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..01a777d 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,66 @@
 
 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..61641d3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/GerritGitilesAccess.java
@@ -21,7 +21,9 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.config.AnonymousCowardName;
+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,13 +33,17 @@
 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.RepositoryNotFoundException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 
@@ -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/GitilesWeblinks.java b/src/main/java/com/googlesource/gerrit/plugins/gitiles/GitilesWeblinks.java
index 61d621a..cf0e9df 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitiles/GitilesWeblinks.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitiles/GitilesWeblinks.java
@@ -15,6 +15,7 @@
 package com.googlesource.gerrit.plugins.gitiles;
 
 import com.google.common.base.MoreObjects;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.common.WebLinkInfo;
 import com.google.gerrit.extensions.webui.BranchWebLink;
@@ -24,9 +25,12 @@
 import com.google.gerrit.extensions.webui.PatchSetWebLink;
 import com.google.gerrit.extensions.webui.ProjectWebLink;
 import com.google.gerrit.extensions.webui.TagWebLink;
+import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.net.MalformedURLException;
+import java.net.URL;
 import org.eclipse.jgit.lib.Config;
 
 @Singleton
@@ -43,10 +47,23 @@
   private final String target;
 
   @Inject
-  public GitilesWeblinks(@PluginName String pluginName, PluginConfigFactory configFactory) {
+  public GitilesWeblinks(
+      @PluginName String pluginName,
+      @Nullable @CanonicalWebUrl String gerritUrl,
+      PluginConfigFactory configFactory)
+      throws MalformedURLException {
+
+    String baseGerritUrl;
+    if (gerritUrl != null) {
+      URL u = new URL(gerritUrl);
+      baseGerritUrl = u.getPath();
+    } else {
+      baseGerritUrl = "/";
+    }
+
     Config config = configFactory.getGlobalPluginConfig("gitiles");
     name = MoreObjects.firstNonNull(config.getString("gerrit", null, "linkname"), "browse");
-    baseUrl = "plugins/" + pluginName;
+    baseUrl = baseGerritUrl + "plugins/" + pluginName;
 
     target = MoreObjects.firstNonNull(config.getString("gerrit", null, "target"), Target.BLANK);
   }
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 acfda5f..71f45ec 100644
--- a/tools/bzl/maven_jar.bzl
+++ b/tools/bzl/maven_jar.bzl
@@ -1 +1 @@
-load("@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", "maven_jar", "GERRIT", "MAVEN_CENTRAL")
+load("@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", "maven_jar", "GERRIT", "MAVEN_CENTRAL", "MAVEN_LOCAL")