Merge branch 'stable-2.15'

* stable-2.15:
  Upgrade bazlets to latest stable-2.15 to build with 2.15.6 API
  WORKSPACE: Make commented out local_path line spaces indent consistent
  Upgrade bazlets to latest stable-2.14 to build with 2.14.16 API
  Upgrade JGit to 4.9.7.201810191756-r
  Upgrade JGit to 4.7.6.201810191618-r
  Add Eclipse project
  Remove redundant entries from .gitignore
  bazlets: Replace native.git_repository with skylark rule
  Harmonize external dependency names to use hyphen
  Upgrade JGit to 4.9.6.201810051924-r
  Upgrade bazlets to latest stable-2.15 to build with 2.15.5 API
  Upgrade JGit to 4.7.5.201810051826-r
  Upgrade bazlets to latest stable-2.14 to build with 2.14.15 API
  Update bazlets to latest stable-2.15 to build with 2.15.4 API
  Update bazlets to latest stable-2.14 to build with 2.14.14 API
  Documentation: Fix non-terminated namespace pattern
  Upgrade JGit to 4.9.5.201809180939-r
  Migrate `tools/bazel.rc` to `.bazelrc`
  Upgrade JGit to 4.7.4.201809180905-r
  Update bazlets to latest stable-2.14 to build with 2.14.13 API
  Add handling of HTTP Conditional GET request to LFS over FS backend
  LfsApiServlet: Fix permission backend check for project access
  Remove Basic authentication placeholder
  Update bazlets to latest stable-2.14 to use 2.14.12 API
  Upgrade JGit to 4.7.2.201807261330-r
  Update bazlets to latest stable-2.14 to use 2.14.11 API
  Format build files with buildifier
  Update bazlets to latest stable-2.14 to use 2.14.10 API
  Update bazlets to latest stable-2.14 to use 2.14.9 API
  Update bazlets to latest revision on stable-2.14

This merge also adjusts the bazlets revision to the latest on the
master branch, which allows to build with 2.16-rc1.

Change-Id: Ide07ebca783ee7028fe293a51078c3585c797d9f
diff --git a/tools/bazel.rc b/.bazelrc
similarity index 100%
rename from tools/bazel.rc
rename to .bazelrc
diff --git a/.gitignore b/.gitignore
index 696ab76..72d1580 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,9 @@
-/bucklets
-/.buckversion
 /.classpath
 /.project
-/.buckd
-/.watchmanconfig
-/buck-out
+/.settings
 /bazel-bin
 /bazel-genfiles
 /bazel-out
 /bazel-lfs
 /bazel-testlogs
+/eclipse-out
diff --git a/.settings/org.eclipse.core.runtime.prefs b/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..8667cfd
--- /dev/null
+++ b/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Tue Sep 02 16:59:24 PDT 2008
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/BUILD b/BUILD
index c0ab3f5..2f873b7 100644
--- a/BUILD
+++ b/BUILD
@@ -18,9 +18,9 @@
     ],
     resources = glob(["src/main/resources/**/*"]),
     deps = [
-        "@jgit_http_apache//jar",
-        "@jgit_lfs//jar",
-        "@jgit_lfs_server//jar",
+        "@jgit-http-apache//jar",
+        "@jgit-lfs-server//jar",
+        "@jgit-lfs//jar",
     ],
 )
 
@@ -39,7 +39,7 @@
     visibility = ["//visibility:public"],
     exports = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
         ":lfs__plugin",
-        "@jgit_lfs//jar",
-        "@joda_time//jar",
+        "@jgit-lfs//jar",
+        "@joda-time//jar",
     ],
 )
diff --git a/WORKSPACE b/WORKSPACE
index 7a31e49..8efe5c2 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,27 +3,27 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "3a53199198db3f49a43b7708c2c3352670393717",
-    #    local_path = "/home/<user>/projects/bazlets",
+    commit = "cc2766bbec1af19eb4d1ed2f32e4ed9a503df32b",
+    #local_path = "/home/<user>/projects/bazlets",
 )
 
 # Release Plugin API
-#load(
-#    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
-#    "gerrit_api",
-#)
-
-# Snapshot Plugin API
 load(
-    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
-    "gerrit_api_maven_local",
+    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
+    "gerrit_api",
 )
 
+# Snapshot Plugin API
+#load(
+#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
+#    "gerrit_api_maven_local",
+#)
+
 # Load release Plugin API
-#gerrit_api()
+gerrit_api()
 
 # Load snapshot Plugin API
-gerrit_api_maven_local()
+#gerrit_api_maven_local()
 
 load(":external_plugin_deps.bzl", "external_plugin_deps")
 
diff --git a/bazlets.bzl b/bazlets.bzl
index b7ce55a..f089af4 100644
--- a/bazlets.bzl
+++ b/bazlets.bzl
@@ -1,18 +1,18 @@
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+
 NAME = "com_googlesource_gerrit_bazlets"
 
 def load_bazlets(
-    commit,
-    local_path = None
-  ):
-  if not local_path:
-      native.git_repository(
-          name = NAME,
-          remote = "https://gerrit.googlesource.com/bazlets",
-          commit = commit,
-      )
-  else:
-      native.local_repository(
-          name = NAME,
-          path = local_path,
-      )
-
+        commit,
+        local_path = None):
+    if not local_path:
+        git_repository(
+            name = NAME,
+            remote = "https://gerrit.googlesource.com/bazlets",
+            commit = commit,
+        )
+    else:
+        native.local_repository(
+            name = NAME,
+            path = local_path,
+        )
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index 0e282c2..41b3259 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -1,48 +1,47 @@
-load("//tools/bzl:maven_jar.bzl", "maven_jar", "GERRIT", "MAVEN_LOCAL", "MAVEN_CENTRAL")
+load("//tools/bzl:maven_jar.bzl", "GERRIT", "MAVEN_CENTRAL", "MAVEN_LOCAL", "maven_jar")
 
-JGIT_VERSION = '5.1.1.201809181055-r'
+JGIT_VERSION = "5.1.1.201809181055-r"
 REPO = MAVEN_CENTRAL
 
 def external_plugin_deps():
-  maven_jar(
-    name = 'jgit_http_apache',
-    artifact = 'org.eclipse.jgit:org.eclipse.jgit.http.apache:' + JGIT_VERSION,
-    sha1 = '236c4ba73978801d7ab04f78eb321d66d7530b8e',
-    repository = REPO,
-    unsign = True,
-    exclude = [
-      'about.html',
-      'plugin.properties',
-    ],
-  )
+    maven_jar(
+        name = "jgit-http-apache",
+        artifact = "org.eclipse.jgit:org.eclipse.jgit.http.apache:" + JGIT_VERSION,
+        sha1 = "236c4ba73978801d7ab04f78eb321d66d7530b8e",
+        repository = REPO,
+        unsign = True,
+        exclude = [
+            "about.html",
+            "plugin.properties",
+        ],
+    )
 
-  maven_jar(
-    name = 'jgit_lfs',
-    artifact = 'org.eclipse.jgit:org.eclipse.jgit.lfs:' + JGIT_VERSION,
-    sha1 = '73ad88fa00f0756a4bc893cdc95818da1adbd188',
-    repository = REPO,
-    unsign = True,
-    exclude = [
-      'about.html',
-      'plugin.properties',
-    ],
-  )
+    maven_jar(
+        name = "jgit-lfs",
+        artifact = "org.eclipse.jgit:org.eclipse.jgit.lfs:" + JGIT_VERSION,
+        sha1 = "73ad88fa00f0756a4bc893cdc95818da1adbd188",
+        repository = REPO,
+        unsign = True,
+        exclude = [
+            "about.html",
+            "plugin.properties",
+        ],
+    )
 
-  maven_jar(
-    name = 'jgit_lfs_server',
-    artifact = 'org.eclipse.jgit:org.eclipse.jgit.lfs.server:' + JGIT_VERSION,
-    sha1 = 'f9389d44beddaf0ecb31065c570caa916d0508de',
-    repository = REPO,
-    unsign = True,
-    exclude = [
-      'about.html',
-      'plugin.properties',
-    ],
-  )
+    maven_jar(
+        name = "jgit-lfs-server",
+        artifact = "org.eclipse.jgit:org.eclipse.jgit.lfs.server:" + JGIT_VERSION,
+        sha1 = "f9389d44beddaf0ecb31065c570caa916d0508de",
+        repository = REPO,
+        unsign = True,
+        exclude = [
+            "about.html",
+            "plugin.properties",
+        ],
+    )
 
-  maven_jar(
-    name = 'joda_time',
-    artifact = 'joda-time:joda-time:2.9.9',
-    sha1 = 'f7b520c458572890807d143670c9b24f4de90897',
-  )
-
+    maven_jar(
+        name = "joda-time",
+        artifact = "joda-time:joda-time:2.9.9",
+        sha1 = "f7b520c458572890807d143670c9b24f4de90897",
+    )
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java
index 0036181..583af07 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java
@@ -18,8 +18,8 @@
 import static com.google.gerrit.extensions.api.lfs.LfsDefinitions.LFS_URL_REGEX_TEMPLATE;
 import static com.google.gerrit.extensions.client.ProjectState.HIDDEN;
 import static com.google.gerrit.extensions.client.ProjectState.READ_ONLY;
-import static com.google.gerrit.server.permissions.ProjectPermission.PUSH_AT_LEAST_ONE_REF;
 import static com.google.gerrit.server.permissions.ProjectPermission.READ;
+import static com.google.gerrit.server.permissions.ProjectPermission.PUSH_AT_LEAST_ONE_REF;
 
 import com.google.gerrit.common.ProjectUtil;
 import com.google.gerrit.reviewdb.client.Project;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsContentServlet.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsContentServlet.java
index 5bdb4d8..cdb5ab1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsContentServlet.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsContentServlet.java
@@ -18,10 +18,13 @@
 import static org.eclipse.jgit.lfs.lib.Constants.UPLOAD;
 import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
 
+import com.google.common.base.Strings;
+import com.google.common.net.HttpHeaders;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 import java.io.IOException;
 import java.text.MessageFormat;
+import java.util.Optional;
 import javax.servlet.AsyncContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -54,34 +57,29 @@
   }
 
   @Override
+  protected void doHead(HttpServletRequest req, HttpServletResponse rsp)
+      throws ServletException, IOException {
+    String verifyId = req.getHeader(HttpHeaders.IF_NONE_MATCH);
+    if (Strings.isNullOrEmpty(verifyId)) {
+      doGet(req, rsp);
+      return;
+    }
+
+    Optional<AnyLongObjectId> obj = validateGetRequest(req, rsp);
+    if (obj.isPresent() && obj.get().getName().equalsIgnoreCase(verifyId)) {
+      rsp.addHeader(HttpHeaders.ETAG, obj.get().getName());
+      rsp.setStatus(HttpStatus.SC_NOT_MODIFIED);
+      return;
+    }
+
+    getObject(req, rsp, obj);
+  }
+
+  @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse rsp)
       throws ServletException, IOException {
-    AnyLongObjectId obj = getObjectToTransfer(req, rsp);
-    if (obj == null) {
-      return;
-    }
-
-    if (repository.getSize(obj) == -1) {
-      sendError(
-          rsp,
-          HttpStatus.SC_NOT_FOUND,
-          MessageFormat.format(LfsServerText.get().objectNotFound, obj.getName()));
-      return;
-    }
-
-    if (!authorizer.verifyAuthInfo(req.getHeader(HDR_AUTHORIZATION), DOWNLOAD, obj)) {
-      sendError(
-          rsp,
-          HttpStatus.SC_UNAUTHORIZED,
-          MessageFormat.format(
-              LfsServerText.get().failedToCalcSignature, "Invalid authorization token"));
-      return;
-    }
-
-    AsyncContext context = req.startAsync();
-    context.setTimeout(timeout);
-    rsp.getOutputStream()
-        .setWriteListener(new ObjectDownloadListener(repository, context, rsp, obj));
+    Optional<AnyLongObjectId> obj = validateGetRequest(req, rsp);
+    getObject(req, rsp, obj);
   }
 
   @Override
@@ -106,4 +104,41 @@
     req.getInputStream()
         .setReadListener(new ObjectUploadListener(repository, context, req, rsp, id));
   }
+
+  private Optional<AnyLongObjectId> validateGetRequest(
+      HttpServletRequest req, HttpServletResponse rsp) throws IOException {
+    AnyLongObjectId obj = getObjectToTransfer(req, rsp);
+    if (obj == null) {
+      return Optional.empty();
+    }
+
+    if (repository.getSize(obj) == -1) {
+      sendError(
+          rsp,
+          HttpStatus.SC_NOT_FOUND,
+          MessageFormat.format(LfsServerText.get().objectNotFound, obj.getName()));
+      return Optional.empty();
+    }
+
+    if (!authorizer.verifyAuthInfo(req.getHeader(HDR_AUTHORIZATION), DOWNLOAD, obj)) {
+      sendError(
+          rsp,
+          HttpStatus.SC_UNAUTHORIZED,
+          MessageFormat.format(
+              LfsServerText.get().failedToCalcSignature, "Invalid authorization token"));
+      return Optional.empty();
+    }
+    return Optional.of(obj);
+  }
+
+  private void getObject(
+      HttpServletRequest req, HttpServletResponse rsp, Optional<AnyLongObjectId> obj)
+      throws IOException {
+    if (obj.isPresent()) {
+      AsyncContext context = req.startAsync();
+      context.setTimeout(timeout);
+      rsp.getOutputStream()
+          .setWriteListener(new ObjectDownloadListener(repository, context, rsp, obj.get()));
+    }
+  }
 }
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 7f44b04..f71464f 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -62,5 +62,13 @@
   bazel test plugins/@PLUGIN@:@PLUGIN@_tests
 ```
 
+This project can be imported into the Eclipse IDE. Execute:
+
+```
+  ./tools/eclipse/project.sh
+```
+
+to generate the required files and then import the project.
+
 How to build the Gerrit Plugin API is described in the [Gerrit
 documentation](../../../Documentation/dev-bazel.html#_extension_and_plugin_api_jar_files).
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 6ad69fe..3013f5c 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -50,7 +50,7 @@
 folders:
 
 ```
-  [@PLUGIN@ "test/*]
+  [@PLUGIN@ "test/*"]
     enabled = true
   [@PLUGIN@ "?/*"]
     enabled = true
diff --git a/tools/bzl/classpath.bzl b/tools/bzl/classpath.bzl
new file mode 100644
index 0000000..d5764f7
--- /dev/null
+++ b/tools/bzl/classpath.bzl
@@ -0,0 +1,4 @@
+load(
+    "@com_googlesource_gerrit_bazlets//tools:classpath.bzl",
+    "classpath_collector",
+)
diff --git a/tools/bzl/maven_jar.bzl b/tools/bzl/maven_jar.bzl
index 4bc37e1..21fb670 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_LOCAL", "MAVEN_CENTRAL")
+load("@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", "GERRIT", "MAVEN_CENTRAL", "MAVEN_LOCAL", "maven_jar")
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
index a2e438f..0b25d23 100644
--- a/tools/bzl/plugin.bzl
+++ b/tools/bzl/plugin.bzl
@@ -1,6 +1,6 @@
 load(
     "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
-    "gerrit_plugin",
     "PLUGIN_DEPS",
     "PLUGIN_TEST_DEPS",
+    "gerrit_plugin",
 )
diff --git a/tools/eclipse/BUILD b/tools/eclipse/BUILD
new file mode 100644
index 0000000..56fe7de
--- /dev/null
+++ b/tools/eclipse/BUILD
@@ -0,0 +1,9 @@
+load("//tools/bzl:classpath.bzl", "classpath_collector")
+
+classpath_collector(
+    name = "main_classpath_collect",
+    testonly = 1,
+    deps = [
+        "//:lfs__plugin_test_deps",
+    ],
+)
diff --git a/tools/eclipse/project.sh b/tools/eclipse/project.sh
new file mode 100755
index 0000000..2e79913
--- /dev/null
+++ b/tools/eclipse/project.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright (C) 2017 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.
+
+`bazel query @com_googlesource_gerrit_bazlets//tools/eclipse:project --output location | sed s/BUILD:.*//`project.py -n lfs -r .