experimental_repository_cache: support relative paths

...and interpret them relative to the workspace directory.

Improves on #3516. In fact, fixes the original request of
supporting relative paths.

Change-Id: Ibbb6fd43179d589ad477427e47e26c773c7a04de
PiperOrigin-RevId: 185121629
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
index 9012ed4..d535867 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
@@ -199,7 +199,15 @@
     RepositoryOptions repoOptions = env.getOptions().getOptions(RepositoryOptions.class);
     if (repoOptions != null) {
       if (repoOptions.experimentalRepositoryCache != null) {
-        Path repositoryCachePath = filesystem.getPath(repoOptions.experimentalRepositoryCache);
+        Path repositoryCachePath;
+        if (repoOptions.experimentalRepositoryCache.isAbsolute()) {
+          repositoryCachePath = filesystem.getPath(repoOptions.experimentalRepositoryCache);
+        } else {
+          repositoryCachePath =
+              env.getBlazeWorkspace()
+                  .getWorkspace()
+                  .getRelative(repoOptions.experimentalRepositoryCache);
+        }
         repositoryCache.setRepositoryCachePath(repositoryCachePath);
       } else {
         repositoryCache.setRepositoryCachePath(null);
diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD
index a376914..3df2ee2 100644
--- a/src/test/shell/bazel/BUILD
+++ b/src/test/shell/bazel/BUILD
@@ -238,7 +238,7 @@
     size = "large",
     srcs = ["external_integration_test.sh"],
     data = [":test-deps"],
-    shard_count = 6,
+    shard_count = 12,
 )
 
 sh_test(
diff --git a/src/test/shell/bazel/external_integration_test.sh b/src/test/shell/bazel/external_integration_test.sh
index cc3b18a..0cbc64c 100755
--- a/src/test/shell/bazel/external_integration_test.sh
+++ b/src/test/shell/bazel/external_integration_test.sh
@@ -1095,6 +1095,79 @@
   expect_log '@ext//:foo'
 }
 
+function test_repository_cache_relative_path() {
+  # Verify that --experimental_repository_cache works for query and caches soly
+  # based on the predicted hash, for a repository-cache location given as path
+  # relative to the WORKSPACE
+  WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX")
+  cd "${WRKDIR}"
+  mkdir ext
+  cat > ext/BUILD <<'EOF'
+genrule(
+  name="foo",
+  outs=["foo.txt"],
+  cmd="echo Hello World > $@",
+)
+genrule(
+  name="bar",
+  outs=["bar.txt"],
+  srcs=[":foo"],
+  cmd="cp $< $@",
+)
+EOF
+  zip ext.zip ext/*
+  rm -rf ext
+  sha256=$(sha256sum ext.zip | head -c 64)
+
+  rm -rf cache
+  mkdir cache
+
+  rm -rf main
+  mkdir main
+  cd main
+  cat > WORKSPACE <<EOF
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+  name="ext",
+  strip_prefix="ext",
+  urls=["file://${WRKDIR}/ext.zip"],
+  sha256="${sha256}",
+)
+EOF
+  # Use the external repository once to make sure it is cached.
+  bazel build --experimental_repository_cache="../cache" '@ext//:bar' \
+      || fail "expected sucess"
+
+  # Now "go offline" and clean local resources.
+  rm -f "${WRKDIR}/ext.zip"
+  bazel clean --expunge
+  bazel query 'deps("@ext//:bar")' && fail "Couldn't clean local cache" || :
+
+  # The value should still be available from the repository cache
+  bazel query 'deps("@ext//:bar")' \
+        --experimental_repository_cache="../cache" > "${TEST_log}" \
+      || fail "Expected success"
+  expect_log '@ext//:foo'
+
+  # Clean again.
+  bazel clean --expunge
+  # Even with a different source URL, the cache sould be consulted.
+
+  cat > WORKSPACE <<EOF
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+  name="ext",
+  strip_prefix="ext",
+  urls=["http://doesnotexist.example.com/invalidpath/othername.zip"],
+  sha256="${sha256}",
+)
+EOF
+  bazel query 'deps("@ext//:bar")' \
+        --experimental_repository_cache="../cache" > "${TEST_log}" \
+      || fail "Expected success"
+  expect_log '@ext//:foo'
+}
+
 function test_repository_cache() {
   # Verify that --experimental_repository_cache works for query and caches soly
   # based on the predicted hash.