diff --git a/src/test/py/bazel/bzlmod/bazel_module_test.py b/src/test/py/bazel/bzlmod/bazel_module_test.py
index 301477560bb224..ddc3b59364b687 100644
--- a/src/test/py/bazel/bzlmod/bazel_module_test.py
+++ b/src/test/py/bazel/bzlmod/bazel_module_test.py
@@ -694,5 +694,68 @@ def testRunfilesRepoMappingManifest(self):
self.Path('bazel-bin/external/bar~2.0/bar.runfiles_manifest')) as f:
self.assertIn('_repo_mapping ', f.read())
+ def testJavaRunfilesLibraryRepoMapping(self):
+ self.main_registry.setModuleBasePath('projects')
+ projects_dir = self.main_registry.projects
+
+ self.main_registry.createLocalPathModule('data', '1.0', 'data')
+ projects_dir.joinpath('data').mkdir(exist_ok=True)
+ scratchFile(projects_dir.joinpath('data', 'WORKSPACE'))
+ scratchFile(projects_dir.joinpath('data', 'foo.txt'), ['hello'])
+ scratchFile(projects_dir.joinpath('data', 'BUILD'),
+ ['exports_files(["foo.txt"])'])
+
+ self.main_registry.createLocalPathModule('test', '1.0', 'test',
+ {'data': '1.0'})
+ projects_dir.joinpath('test').mkdir(exist_ok=True)
+ scratchFile(projects_dir.joinpath('test', 'WORKSPACE'))
+ scratchFile(projects_dir.joinpath('test', 'BUILD'), [
+ 'java_test(',
+ ' name = "test",'
+ ' srcs = ["Test.java"],',
+ ' main_class = "com.example.Test",',
+ ' use_testrunner = False,',
+ ' data = ["@data//:foo.txt"],',
+ ' args = ["$(rlocationpath @data//:foo.txt)"],',
+ ' deps = ["@bazel_tools//tools/java/runfiles"],',
+ ')'
+ ])
+ scratchFile(projects_dir.joinpath('test', 'Test.java'), [
+ 'package com.example;',
+ '',
+ 'import com.google.devtools.build.runfiles.AutoBazelRepository;',
+ 'import com.google.devtools.build.runfiles.Runfiles;',
+ '',
+ 'import java.io.File;',
+ 'import java.io.IOException;',
+ '',
+ '@AutoBazelRepository',
+ 'public class Test {',
+ ' public static void main(String[] args) throws IOException {',
+ ' Runfiles.Preloaded rp = Runfiles.preload();',
+ ' if (!new File(rp.unmapped().rlocation(args[0])).exists()) {',
+ ' System.exit(1);',
+ ' }',
+ ' if (!new File(rp.withSourceRepository(AutoBazelRepository_Test.NAME).rlocation("data/foo.txt")).exists()) {',
+ ' System.exit(1);',
+ ' }',
+ ' }',
+ '}',
+ ])
+
+ self.ScratchFile('MODULE.bazel', ['bazel_dep(name="test",version="1.0")'])
+ self.ScratchFile('WORKSPACE')
+
+ # Run sandboxed on Linux and macOS.
+ exit_code, stderr, stdout = self.RunBazel(
+ ['test', '@test//:test', '--test_output=errors',
+ '--test_env=RUNFILES_LIB_DEBUG=1'], allow_failure=True)
+ self.AssertExitCode(exit_code, 0, stderr, stdout)
+ # Run unsandboxed on all platforms.
+ exit_code, stderr, stdout = self.RunBazel(
+ ['run', '@test//:test'], allow_failure=True,
+ env_add={"RUNFILES_LIB_DEBUG": "1"})
+ self.AssertExitCode(exit_code, 0, stderr, stdout)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/java/runfiles/Runfiles.java b/tools/java/runfiles/Runfiles.java
index 9a3aa26c4517a9..5d75e093a78ae2 100644
--- a/tools/java/runfiles/Runfiles.java
+++ b/tools/java/runfiles/Runfiles.java
@@ -17,12 +17,16 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.lang.ref.SoftReference;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
/**
* Runfiles lookup library for Bazel-built Java binaries and tests.
@@ -45,15 +49,58 @@
* import com.google.devtools.build.runfiles.Runfiles;
*
*
- *
3. Create a Runfiles object and use rlocation to look up runfile paths:
+ *
3. Create a {@link Preloaded} object:
*
*
* public void myFunction() {
- * Runfiles runfiles = Runfiles.create();
- * String path = runfiles.rlocation("my_workspace/path/to/my/data.txt");
+ * Runfiles.Preloaded runfiles = Runfiles.preload();
* ...
*
*
+ * 4. To look up a runfile, use either of the following approaches:
+ *
+ *
4a. Annotate the class from which runfiles should be looked up with
+ * {@link AutoBazelRepository} and obtain the name of the Bazel repository containing the class from
+ * a constant generated by this annotation:
+ *
+ *
+ * import com.google.devtools.build.runfiles.AutoBazelRepository;
+ * @AutoBazelRepository
+ * public class MyClass {
+ * public void myFunction() {
+ * Runfiles.Preloaded runfiles = Runfiles.preload();
+ * String path = runfiles.withSourceRepository(AutoBazelRepository_MyClass.NAME)
+ * .rlocation("my_workspace/path/to/my/data.txt");
+ * ...
+ *
+ *
+ *
+ * 4b. Let Bazel compute the path passed to rlocation and pass it into a java_binary
+ * via an argument or an environment variable:
+ *
+ *
+ * java_binary(
+ * name = "my_binary",
+ * srcs = ["MyClass.java"],
+ * data = ["@my_workspace//path/to/my:data.txt"],
+ * env = {"MY_RUNFILE": "$(rlocationpath @my_workspace//path/to/my:data.txt)"},
+ * )
+ *
+ *
+ *
+ * public class MyClass {
+ * public void myFunction() {
+ * Runfiles.Preloaded runfiles = Runfiles.preload();
+ * String path = runfiles.unmapped().rlocation(System.getenv("MY_RUNFILE"));
+ * ...
+ *
+ *
+ *
+ * For more details on why it is required to pass in the current repository name, see
+ * {@see https://bazel.build/build/bzlmod#repository-names}.
+ *
+ * Subprocesses
+ *
* If you want to start subprocesses that also need runfiles, you need to set the right
* environment variables for them:
*
@@ -64,23 +111,138 @@
* ...
* Process p = pb.start();
*
+ *
+ *
{@link Preloaded} vs. {@link Runfiles}
+ *
+ * Instances of {@link Preloaded} are meant to be stored and passed around to other components
+ * that need to access runfiles. They are created by calling {@link Runfiles#preload()}
+ * {@link Runfiles#preload(Map)} and immutably encapsulate all data required to look up runfiles
+ * with the repository mapping of any Bazel repository specified at a later time.
+ *
+ *
Creating {@link Runfiles} instances can be costly, so applications should try to create as few
+ * instances as possible. {@link Runfiles#preload()}, but not {@link Runfiles#preload(Map)}, returns
+ * a single global, softly cached instance of {@link Preloaded} that is constructed based on the
+ * JVM's environment variables.
+ *
+ *
Instance of {@link Runfiles} are only meant to be used by code located in a single Bazel
+ * repository and should not be passed around. They are created by calling
+ * {@link Preloaded#withSourceRepository(String)} or {@link Preloaded#unmapped()} and in addition to
+ * the data in {@link Preloaded} also fix a source repository relative to which apparent repository
+ * names are resolved.
+ *
+ *
Creating {@link Preloaded} instances is cheap.
*/
-public abstract class Runfiles {
+public final class Runfiles {
+
+ /**
+ * A class that encapsulates all data required to look up runfiles relative to any Bazel
+ * repository fixed at a later time.
+ *
+ *
This class is immutable.
+ */
+ public abstract static class Preloaded {
+
+ /**
+ * See {@link com.google.devtools.build.lib.analysis.RepoMappingManifestAction.Entry}.
+ */
+ static class RepoMappingKey {
+
+ public final String sourceRepo;
+ public final String targetRepoApparentName;
+
+ public RepoMappingKey(String sourceRepo, String targetRepoApparentName) {
+ this.sourceRepo = sourceRepo;
+ this.targetRepoApparentName = targetRepoApparentName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RepoMappingKey that = (RepoMappingKey) o;
+ return sourceRepo.equals(that.sourceRepo) && targetRepoApparentName.equals(
+ that.targetRepoApparentName);
+ }
- // Package-private constructor, so only package-private classes may extend it.
- private Runfiles() {}
+ @Override
+ public int hashCode() {
+ return Objects.hash(sourceRepo, targetRepoApparentName);
+ }
+ }
+
+ /**
+ * Returns a {@link Runfiles} instance that uses the provided source repository's repository
+ * mapping to translate apparent into canonical repository names.
+ *
+ *
{@see https://bazel.build/build/bzlmod#repository-names}
+ *
+ * @param sourceRepository the canonical name of the Bazel repository relative to which apparent
+ * repository names should be resolved. Should generally coincide with
+ * the Bazel repository that contains the caller of this method, which
+ * can be obtained via {@link AutoBazelRepository}.
+ * @return a {@link Runfiles} instance that looks up runfiles relative to the provided source
+ * repository and shares all other data with this {@link Preloaded} instance.
+ */
+ public final Runfiles withSourceRepository(String sourceRepository) {
+ Util.checkArgument(sourceRepository != null);
+ return new Runfiles(this, sourceRepository);
+ }
+
+ /**
+ * Returns a {@link Runfiles} instance backed by the preloaded runfiles data that can be used to
+ * look up runfiles paths with canonical repository names only.
+ *
+ * @return a {@link Runfiles} instance that can only look up paths with canonical repository
+ * names and shared all data with this {@link Preloaded} instance.
+ */
+ public final Runfiles unmapped() {
+ return new Runfiles(this, null);
+ }
+
+ protected abstract Map getEnvVars();
+
+ protected abstract String rlocationChecked(String path);
+
+ protected abstract Map getRepoMapping();
+
+ // Private constructor, so only nested classes may extend it.
+ private Preloaded() {
+ }
+ }
+
+ private static final String MAIN_REPOSITORY = "";
+
+ private static SoftReference DEFAULT_INSTANCE = new SoftReference<>(null);
+
+ private final Preloaded preloadedRunfiles;
+ private final String sourceRepository;
+
+ private Runfiles(Preloaded preloadedRunfiles, String sourceRepository) {
+ this.preloadedRunfiles = preloadedRunfiles;
+ this.sourceRepository = sourceRepository;
+ }
/**
- * Returns a new {@link Runfiles} instance.
+ * Returns the softly cached global {@link Runfiles.Preloaded} instance, creating it if needed.
*
* This method passes the JVM's environment variable map to {@link #create(Map)}.
*/
- public static Runfiles create() throws IOException {
- return create(System.getenv());
+ public static synchronized Preloaded preload() throws IOException {
+ Preloaded instance = DEFAULT_INSTANCE.get();
+ if (instance != null) {
+ return instance;
+ }
+ instance = preload(System.getenv());
+ DEFAULT_INSTANCE = new SoftReference<>(instance);
+ return instance;
}
/**
- * Returns a new {@link Runfiles} instance.
+ * Returns a new {@link Runfiles.Preloaded} instance.
*
*
The returned object is either:
*
@@ -101,10 +263,10 @@ public static Runfiles create() throws IOException {
* manifest file upon instantiation.
*
* @throws IOException if RUNFILES_MANIFEST_ONLY=1 is in {@code env} but there's no
- * "RUNFILES_MANIFEST_FILE", "RUNFILES_DIR", or "JAVA_RUNFILES" key in {@code env} or their
- * values are empty, or some IO error occurs
+ * "RUNFILES_MANIFEST_FILE", "RUNFILES_DIR", or "JAVA_RUNFILES" key in
+ * {@code env} or their values are empty, or some IO error occurs
*/
- public static Runfiles create(Map env) throws IOException {
+ public static Preloaded preload(Map env) throws IOException {
if (isManifestOnly(env)) {
// On Windows, Bazel sets RUNFILES_MANIFEST_ONLY=1.
// On every platform, Bazel also sets RUNFILES_MANIFEST_FILE, but on Linux and macOS it's
@@ -115,20 +277,66 @@ public static Runfiles create(Map env) throws IOException {
}
}
+ /**
+ * Returns a new {@link Runfiles} instance.
+ *
+ * Deprecated: Use {@link #preload()} instead. With {@code --enable_bzlmod}, this
+ * function does not work correctly.
+ *
+ *
This method passes the JVM's environment variable map to {@link #create(Map)}.
+ */
+ @Deprecated
+ public static Runfiles create() throws IOException {
+ return preload().withSourceRepository(MAIN_REPOSITORY);
+ }
+
+ /**
+ * Returns a new {@link Runfiles} instance.
+ *
+ *
Deprecated: Use {@link #preload(Map)} )} instead. With {@code --enable_bzlmod}, this
+ * function does not work correctly.
+ *
+ *
The returned object is either:
+ *
+ *
+ * - manifest-based, meaning it looks up runfile paths from a manifest file, or
+ *
- directory-based, meaning it looks up runfile paths under a given directory path
+ *
+ *
+ * If {@code env} contains "RUNFILES_MANIFEST_ONLY" with value "1", this method returns a
+ * manifest-based implementation. The manifest's path is defined by the "RUNFILES_MANIFEST_FILE"
+ * key's value in {@code env}.
+ *
+ *
Otherwise this method returns a directory-based implementation. The directory's path is
+ * defined by the value in {@code env} under the "RUNFILES_DIR" key, or if absent, then under the
+ * "JAVA_RUNFILES" key.
+ *
+ *
Note about performance: the manifest-based implementation eagerly reads and caches the whole
+ * manifest file upon instantiation.
+ *
+ * @throws IOException if RUNFILES_MANIFEST_ONLY=1 is in {@code env} but there's no
+ * "RUNFILES_MANIFEST_FILE", "RUNFILES_DIR", or "JAVA_RUNFILES" key in
+ * {@code env} or their values are empty, or some IO error occurs
+ */
+ @Deprecated
+ public static Runfiles create(Map env) throws IOException {
+ return preload(env).withSourceRepository(MAIN_REPOSITORY);
+ }
+
/**
* Returns the runtime path of a runfile (a Bazel-built binary's/test's data-dependency).
*
- * The returned path may not be valid. The caller should check the path's validity and that the
- * path exists.
+ *
The returned path may not be valid. The caller should check the path's validity and that
+ * the path exists.
*
*
The function may return null. In that case the caller can be sure that the rule does not
* know about this data-dependency.
*
* @param path runfiles-root-relative path of the runfile
* @throws IllegalArgumentException if {@code path} fails validation, for example if it's null or
- * empty, or not normalized (contains "./", "../", or "//")
+ * empty, or not normalized (contains "./", "../", or "//")
*/
- public final String rlocation(String path) {
+ public String rlocation(String path) {
Util.checkArgument(path != null);
Util.checkArgument(!path.isEmpty());
Util.checkArgument(
@@ -145,7 +353,19 @@ public final String rlocation(String path) {
if (new File(path).isAbsolute()) {
return path;
}
- return rlocationChecked(path);
+
+ if (sourceRepository == null) {
+ return preloadedRunfiles.rlocationChecked(path);
+ }
+ String[] apparentTargetAndRemainder = path.split("/", 2);
+ if (apparentTargetAndRemainder.length < 2) {
+ return preloadedRunfiles.rlocationChecked(path);
+ }
+ String targetCanonical = preloadedRunfiles.getRepoMapping().getOrDefault(
+ new Preloaded.RepoMappingKey(sourceRepository, apparentTargetAndRemainder[0]),
+ apparentTargetAndRemainder[0]);
+ return preloadedRunfiles.rlocationChecked(
+ targetCanonical + "/" + apparentTargetAndRemainder[1]);
}
/**
@@ -154,9 +374,13 @@ public final String rlocation(String path) {
*
The caller should add the returned key-value pairs to the environment of subprocesses in
* case those subprocesses are also Bazel-built binaries that need to use runfiles.
*/
- public abstract Map getEnvVars();
+ public Map getEnvVars() {
+ return preloadedRunfiles.getEnvVars();
+ }
- /** Returns true if the platform supports runfiles only via manifests. */
+ /**
+ * Returns true if the platform supports runfiles only via manifests.
+ */
private static boolean isManifestOnly(Map env) {
return "1".equals(env.get("RUNFILES_MANIFEST_ONLY"));
}
@@ -183,50 +407,48 @@ private static String getRunfilesDir(Map env) throws IOException
return value;
}
- abstract String rlocationChecked(String path);
+ private static Map loadRepositoryMapping(String path)
+ throws IOException {
+ if (path == null || !new File(path).exists()) {
+ return Collections.emptyMap();
+ }
+
+ try (BufferedReader r = new BufferedReader(new FileReader(path, StandardCharsets.UTF_8))) {
+ return Collections.unmodifiableMap(r.lines()
+ .filter(line -> !line.isEmpty())
+ .map(line -> {
+ String[] split = line.split(",");
+ if (split.length != 3) {
+ throw new IllegalArgumentException(
+ "Invalid line in repository mapping: '" + line + "'");
+ }
+ return split;
+ })
+ .collect(Collectors.toMap(
+ split -> new Preloaded.RepoMappingKey(split[0], split[1]),
+ split -> split[2])));
+ }
+ }
+
+ /**
+ * {@link Runfiles} implementation that parses a runfiles-manifest file to look up runfiles.
+ */
+ private static final class ManifestBased extends Runfiles.Preloaded {
- /** {@link Runfiles} implementation that parses a runfiles-manifest file to look up runfiles. */
- private static final class ManifestBased extends Runfiles {
private final Map runfiles;
private final String manifestPath;
+ private final Map repoMapping;
ManifestBased(String manifestPath) throws IOException {
Util.checkArgument(manifestPath != null);
Util.checkArgument(!manifestPath.isEmpty());
this.manifestPath = manifestPath;
this.runfiles = loadRunfiles(manifestPath);
- }
-
- private static Map loadRunfiles(String path) throws IOException {
- HashMap result = new HashMap<>();
- try (BufferedReader r =
- new BufferedReader(
- new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8))) {
- String line = null;
- while ((line = r.readLine()) != null) {
- int index = line.indexOf(' ');
- String runfile = (index == -1) ? line : line.substring(0, index);
- String realPath = (index == -1) ? line : line.substring(index + 1);
- result.put(runfile, realPath);
- }
- }
- return Collections.unmodifiableMap(result);
- }
-
- private static String findRunfilesDir(String manifest) {
- if (manifest.endsWith("/MANIFEST")
- || manifest.endsWith("\\MANIFEST")
- || manifest.endsWith(".runfiles_manifest")) {
- String path = manifest.substring(0, manifest.length() - 9);
- if (new File(path).isDirectory()) {
- return path;
- }
- }
- return "";
+ this.repoMapping = loadRepositoryMapping(rlocationChecked("_repo_mapping"));
}
@Override
- public String rlocationChecked(String path) {
+ protected String rlocationChecked(String path) {
String exactMatch = runfiles.get(path);
if (exactMatch != null) {
return exactMatch;
@@ -245,7 +467,7 @@ public String rlocationChecked(String path) {
}
@Override
- public Map getEnvVars() {
+ protected Map getEnvVars() {
HashMap result = new HashMap<>(4);
result.put("RUNFILES_MANIFEST_ONLY", "1");
result.put("RUNFILES_MANIFEST_FILE", manifestPath);
@@ -255,25 +477,68 @@ public Map getEnvVars() {
result.put("JAVA_RUNFILES", runfilesDir);
return result;
}
+
+ @Override
+ protected Map getRepoMapping() {
+ return repoMapping;
+ }
+
+ private static Map loadRunfiles(String path) throws IOException {
+ HashMap result = new HashMap<>();
+ try (BufferedReader r =
+ new BufferedReader(
+ new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8))) {
+ String line = null;
+ while ((line = r.readLine()) != null) {
+ int index = line.indexOf(' ');
+ String runfile = (index == -1) ? line : line.substring(0, index);
+ String realPath = (index == -1) ? line : line.substring(index + 1);
+ result.put(runfile, realPath);
+ }
+ }
+ return Collections.unmodifiableMap(result);
+ }
+
+ private static String findRunfilesDir(String manifest) {
+ if (manifest.endsWith("/MANIFEST")
+ || manifest.endsWith("\\MANIFEST")
+ || manifest.endsWith(".runfiles_manifest")) {
+ String path = manifest.substring(0, manifest.length() - 9);
+ if (new File(path).isDirectory()) {
+ return path;
+ }
+ }
+ return "";
+ }
}
- /** {@link Runfiles} implementation that appends runfiles paths to the runfiles root. */
- private static final class DirectoryBased extends Runfiles {
+ /**
+ * {@link Runfiles} implementation that appends runfiles paths to the runfiles root.
+ */
+ private static final class DirectoryBased extends Preloaded {
+
private final String runfilesRoot;
+ private final Map repoMapping;
- DirectoryBased(String runfilesDir) {
+ DirectoryBased(String runfilesDir) throws IOException {
Util.checkArgument(!Util.isNullOrEmpty(runfilesDir));
Util.checkArgument(new File(runfilesDir).isDirectory());
this.runfilesRoot = runfilesDir;
+ this.repoMapping = loadRepositoryMapping(rlocationChecked("_repo_mapping"));
}
@Override
- String rlocationChecked(String path) {
+ protected String rlocationChecked(String path) {
return runfilesRoot + "/" + path;
}
@Override
- public Map getEnvVars() {
+ protected Map getRepoMapping() {
+ return repoMapping;
+ }
+
+ @Override
+ protected Map getEnvVars() {
HashMap result = new HashMap<>(2);
result.put("RUNFILES_DIR", runfilesRoot);
// TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can pick up RUNFILES_DIR.
@@ -282,11 +547,11 @@ public Map getEnvVars() {
}
}
- static Runfiles createManifestBasedForTesting(String manifestPath) throws IOException {
+ static Preloaded createManifestBasedForTesting(String manifestPath) throws IOException {
return new ManifestBased(manifestPath);
}
- static Runfiles createDirectoryBasedForTesting(String runfilesDir) {
+ static Preloaded createDirectoryBasedForTesting(String runfilesDir) throws IOException {
return new DirectoryBased(runfilesDir);
}
}
diff --git a/tools/java/runfiles/testing/BUILD b/tools/java/runfiles/testing/BUILD
index 82d7836e16cde3..841724b36dc453 100644
--- a/tools/java/runfiles/testing/BUILD
+++ b/tools/java/runfiles/testing/BUILD
@@ -36,7 +36,6 @@ java_library(
name = "test_deps",
testonly = 1,
exports = [
- ":mock-file",
"//third_party:guava",
"//third_party:guava-testlib",
"//third_party:junit4",
@@ -44,11 +43,3 @@ java_library(
"//tools/java/runfiles",
],
)
-
-java_library(
- name = "mock-file",
- testonly = 1,
- srcs = ["MockFile.java"],
- exports = ["//third_party:guava"],
- deps = ["//third_party:guava"],
-)
diff --git a/tools/java/runfiles/testing/MockFile.java b/tools/java/runfiles/testing/MockFile.java
deleted file mode 100644
index 886bfcbcc82a38..00000000000000
--- a/tools/java/runfiles/testing/MockFile.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2018 The Bazel Authors. All rights reserved.
-//
-// 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.devtools.build.runfiles;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import java.io.Closeable;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-final class MockFile implements Closeable {
-
- public final Path path;
-
- public MockFile(ImmutableList lines) throws IOException {
- String testTmpdir = System.getenv("TEST_TMPDIR");
- if (Strings.isNullOrEmpty(testTmpdir)) {
- throw new IOException("$TEST_TMPDIR is empty or undefined");
- }
- path = Files.createTempFile(new File(testTmpdir).toPath(), null, null);
- Files.write(path, lines, StandardCharsets.UTF_8);
- }
-
- @Override
- public void close() throws IOException {
- if (path != null) {
- Files.delete(path);
- }
- }
-}
diff --git a/tools/java/runfiles/testing/RunfilesTest.java b/tools/java/runfiles/testing/RunfilesTest.java
index e98ca554a8a27d..22605c3bf0952c 100644
--- a/tools/java/runfiles/testing/RunfilesTest.java
+++ b/tools/java/runfiles/testing/RunfilesTest.java
@@ -25,17 +25,23 @@
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Collections;
import java.util.Map;
import javax.annotation.Nullable;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-/** Unit tests for {@link Runfiles}. */
+/**
+ * Unit tests for {@link Runfiles}.
+ */
@RunWith(JUnit4.class)
public final class RunfilesTest {
+ @Rule
+ public TemporaryFolder tempDir = new TemporaryFolder(new File(System.getenv("TEST_TMPDIR")));
+
private static boolean isWindows() {
return File.separatorChar == '\\';
}
@@ -44,7 +50,7 @@ private void assertRlocationArg(Runfiles runfiles, String path, @Nullable String
IllegalArgumentException e =
assertThrows(IllegalArgumentException.class, () -> runfiles.rlocation(path));
if (error != null) {
- assertThat(e).hasMessageThat().contains(error);
+ assertThat(e).hasMessageThat().contains(error);
}
}
@@ -71,24 +77,23 @@ public void testRlocationArgumentValidation() throws Exception {
@Test
public void testCreatesManifestBasedRunfiles() throws Exception {
- try (MockFile mf = new MockFile(ImmutableList.of("a/b c/d"))) {
- Runfiles r =
- Runfiles.create(
- ImmutableMap.of(
- "RUNFILES_MANIFEST_ONLY", "1",
- "RUNFILES_MANIFEST_FILE", mf.path.toString(),
- "RUNFILES_DIR", "ignored when RUNFILES_MANIFEST_ONLY=1",
- "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value",
- "TEST_SRCDIR", "should always be ignored"));
- assertThat(r.rlocation("a/b")).isEqualTo("c/d");
- assertThat(r.rlocation("foo")).isNull();
-
- if (isWindows()) {
- assertThat(r.rlocation("c:/foo")).isEqualTo("c:/foo");
- assertThat(r.rlocation("c:\\foo")).isEqualTo("c:\\foo");
- } else {
- assertThat(r.rlocation("/foo")).isEqualTo("/foo");
- }
+ Path mf = tempFile("foo.runfiles_manifest", ImmutableList.of("a/b c/d"));
+ Runfiles r =
+ Runfiles.create(
+ ImmutableMap.of(
+ "RUNFILES_MANIFEST_ONLY", "1",
+ "RUNFILES_MANIFEST_FILE", mf.toString(),
+ "RUNFILES_DIR", "ignored when RUNFILES_MANIFEST_ONLY=1",
+ "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value",
+ "TEST_SRCDIR", "should always be ignored"));
+ assertThat(r.rlocation("a/b")).isEqualTo("c/d");
+ assertThat(r.rlocation("foo")).isNull();
+
+ if (isWindows()) {
+ assertThat(r.rlocation("c:/foo")).isEqualTo("c:/foo");
+ assertThat(r.rlocation("c:\\foo")).isEqualTo("c:\\foo");
+ } else {
+ assertThat(r.rlocation("/foo")).isEqualTo("/foo");
}
}
@@ -146,7 +151,7 @@ public void testIgnoresTestSrcdirWhenJavaRunfilesIsUndefinedAndJustFails() throw
"RUNFILES_DIR", "",
"JAVA_RUNFILES", "",
"RUNFILES_MANIFEST_FILE",
- "ignored when RUNFILES_MANIFEST_ONLY is not set to 1",
+ "ignored when RUNFILES_MANIFEST_ONLY is not set to 1",
"TEST_SRCDIR", "should always be ignored")));
assertThat(e).hasMessageThat().contains("$RUNFILES_DIR and $JAVA_RUNFILES");
}
@@ -166,12 +171,7 @@ public void testFailsToCreateManifestBasedBecauseManifestDoesNotExist() {
@Test
public void testManifestBasedEnvVars() throws Exception {
- Path dir =
- Files.createTempDirectory(
- FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null);
-
- Path mf = dir.resolve("MANIFEST");
- Files.write(mf, Collections.emptyList(), StandardCharsets.UTF_8);
+ Path mf = tempFile("MANIFEST", ImmutableList.of());
Map envvars =
Runfiles.create(
ImmutableMap.of(
@@ -186,13 +186,12 @@ public void testManifestBasedEnvVars() throws Exception {
"RUNFILES_MANIFEST_ONLY", "RUNFILES_MANIFEST_FILE", "RUNFILES_DIR", "JAVA_RUNFILES");
assertThat(envvars.get("RUNFILES_MANIFEST_ONLY")).isEqualTo("1");
assertThat(envvars.get("RUNFILES_MANIFEST_FILE")).isEqualTo(mf.toString());
- assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(dir.toString());
- assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(dir.toString());
+ assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(tempDir.getRoot().toString());
+ assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(tempDir.getRoot().toString());
- Path rfDir = dir.resolve("foo.runfiles");
+ Path rfDir = tempDir.getRoot().toPath().resolve("foo.runfiles");
Files.createDirectories(rfDir);
- mf = dir.resolve("foo.runfiles_manifest");
- Files.write(mf, Collections.emptyList(), StandardCharsets.UTF_8);
+ mf = tempFile("foo.runfiles_manifest", ImmutableList.of());
envvars =
Runfiles.create(
ImmutableMap.of(
@@ -210,81 +209,339 @@ public void testManifestBasedEnvVars() throws Exception {
@Test
public void testDirectoryBasedEnvVars() throws Exception {
- Path dir =
- Files.createTempDirectory(
- FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null);
-
Map envvars =
Runfiles.create(
ImmutableMap.of(
"RUNFILES_MANIFEST_FILE",
"ignored when RUNFILES_MANIFEST_ONLY is not set to 1",
"RUNFILES_DIR",
- dir.toString(),
+ tempDir.getRoot().toString(),
"JAVA_RUNFILES",
"ignored when RUNFILES_DIR has a value",
"TEST_SRCDIR",
"should always be ignored"))
.getEnvVars();
assertThat(envvars.keySet()).containsExactly("RUNFILES_DIR", "JAVA_RUNFILES");
- assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(dir.toString());
- assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(dir.toString());
+ assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(tempDir.getRoot().toString());
+ assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(tempDir.getRoot().toString());
}
@Test
- public void testDirectoryBasedRlocation() {
+ public void testDirectoryBasedRlocation() throws IOException {
// The DirectoryBased implementation simply joins the runfiles directory and the runfile's path
// on a "/". DirectoryBased does not perform any normalization, nor does it check that the path
// exists.
File dir = new File(System.getenv("TEST_TMPDIR"), "mock/runfiles");
assertThat(dir.mkdirs()).isTrue();
- Runfiles r = Runfiles.createDirectoryBasedForTesting(dir.toString());
+ Runfiles r = Runfiles.createDirectoryBasedForTesting(dir.toString()).withSourceRepository("");
// Escaping for "\": once for string and once for regex.
assertThat(r.rlocation("arg")).matches(".*[/\\\\]mock[/\\\\]runfiles[/\\\\]arg");
}
@Test
public void testManifestBasedRlocation() throws Exception {
- try (MockFile mf =
- new MockFile(
- ImmutableList.of(
- "Foo/runfile1 C:/Actual Path\\runfile1",
- "Foo/Bar/runfile2 D:\\the path\\run file 2.txt",
- "Foo/Bar/Dir E:\\Actual Path\\Directory"))) {
- Runfiles r = Runfiles.createManifestBasedForTesting(mf.path.toString());
- assertThat(r.rlocation("Foo/runfile1")).isEqualTo("C:/Actual Path\\runfile1");
- assertThat(r.rlocation("Foo/Bar/runfile2")).isEqualTo("D:\\the path\\run file 2.txt");
- assertThat(r.rlocation("Foo/Bar/Dir")).isEqualTo("E:\\Actual Path\\Directory");
- assertThat(r.rlocation("Foo/Bar/Dir/File")).isEqualTo("E:\\Actual Path\\Directory/File");
- assertThat(r.rlocation("Foo/Bar/Dir/Deeply/Nested/File"))
- .isEqualTo("E:\\Actual Path\\Directory/Deeply/Nested/File");
- assertThat(r.rlocation("unknown")).isNull();
- }
+ Path mf = tempFile("MANIFEST", ImmutableList.of(
+ "Foo/runfile1 C:/Actual Path\\runfile1",
+ "Foo/Bar/runfile2 D:\\the path\\run file 2.txt",
+ "Foo/Bar/Dir E:\\Actual Path\\Directory"));
+ Runfiles r = Runfiles.createManifestBasedForTesting(mf.toString()).withSourceRepository("");
+ assertThat(r.rlocation("Foo/runfile1")).isEqualTo("C:/Actual Path\\runfile1");
+ assertThat(r.rlocation("Foo/Bar/runfile2")).isEqualTo("D:\\the path\\run file 2.txt");
+ assertThat(r.rlocation("Foo/Bar/Dir")).isEqualTo("E:\\Actual Path\\Directory");
+ assertThat(r.rlocation("Foo/Bar/Dir/File")).isEqualTo("E:\\Actual Path\\Directory/File");
+ assertThat(r.rlocation("Foo/Bar/Dir/Deeply/Nested/File"))
+ .isEqualTo("E:\\Actual Path\\Directory/Deeply/Nested/File");
+ assertThat(r.rlocation("unknown")).isNull();
}
@Test
- public void testDirectoryBasedCtorArgumentValidation() {
- assertThrows(
- IllegalArgumentException.class, () -> Runfiles.createDirectoryBasedForTesting(null));
+ public void testManifestBasedRlocationWithRepoMapping_fromMain() throws Exception {
+ Path rm = tempFile("foo.repo_mapping", ImmutableList.of(
+ ",my_module,_main",
+ ",my_protobuf,protobuf~3.19.2",
+ ",my_workspace,_main",
+ "protobuf~3.19.2,protobuf,protobuf~3.19.2"));
+ Path mf = tempFile("foo.runfiles_manifest", ImmutableList.of(
+ "_repo_mapping " + rm,
+ "config.json /etc/config.json",
+ "protobuf~3.19.2/foo/runfile C:/Actual Path\\protobuf\\runfile",
+ "_main/bar/runfile /the/path/./to/other//other runfile.txt",
+ "protobuf~3.19.2/bar/dir E:\\Actual Path\\Directory"));
+ Runfiles r = Runfiles.createManifestBasedForTesting(mf.toString()).withSourceRepository("");
+
+ assertThat(r.rlocation("my_module/bar/runfile")).isEqualTo(
+ "/the/path/./to/other//other runfile.txt");
+ assertThat(r.rlocation("my_workspace/bar/runfile")).isEqualTo(
+ "/the/path/./to/other//other runfile.txt");
+ assertThat(r.rlocation("my_protobuf/foo/runfile")).isEqualTo(
+ "C:/Actual Path\\protobuf\\runfile");
+ assertThat(r.rlocation("my_protobuf/bar/dir")).isEqualTo("E:\\Actual Path\\Directory");
+ assertThat(r.rlocation("my_protobuf/bar/dir/file")).isEqualTo(
+ "E:\\Actual Path\\Directory/file");
+ assertThat(r.rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ "E:\\Actual Path\\Directory/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("protobuf/foo/runfile")).isNull();
+ assertThat(r.rlocation("protobuf/bar/dir")).isNull();
+ assertThat(r.rlocation("protobuf/bar/dir/file")).isNull();
+ assertThat(r.rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi~le")).isNull();
+
+ assertThat(r.rlocation("_main/bar/runfile")).isEqualTo(
+ "/the/path/./to/other//other runfile.txt");
+ assertThat(r.rlocation("protobuf~3.19.2/foo/runfile")).isEqualTo(
+ "C:/Actual Path\\protobuf\\runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir")).isEqualTo("E:\\Actual Path\\Directory");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/file")).isEqualTo(
+ "E:\\Actual Path\\Directory/file");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ "E:\\Actual Path\\Directory/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("config.json")).isEqualTo("/etc/config.json");
+ assertThat(r.rlocation("_main")).isNull();
+ assertThat(r.rlocation("my_module")).isNull();
+ assertThat(r.rlocation("protobuf")).isNull();
+ }
- assertThrows(IllegalArgumentException.class, () -> Runfiles.createDirectoryBasedForTesting(""));
+ @Test
+ public void testManifestBasedRlocationUnmapped() throws Exception {
+ Path rm = tempFile("foo.repo_mapping", ImmutableList.of(
+ ",my_module,_main",
+ ",my_protobuf,protobuf~3.19.2",
+ ",my_workspace,_main",
+ "protobuf~3.19.2,protobuf,protobuf~3.19.2"));
+ Path mf = tempFile("foo.runfiles_manifest", ImmutableList.of(
+ "_repo_mapping " + rm,
+ "config.json /etc/config.json",
+ "protobuf~3.19.2/foo/runfile C:/Actual Path\\protobuf\\runfile",
+ "_main/bar/runfile /the/path/./to/other//other runfile.txt",
+ "protobuf~3.19.2/bar/dir E:\\Actual Path\\Directory"));
+ Runfiles r = Runfiles.createManifestBasedForTesting(mf.toString()).unmapped();
+
+ assertThat(r.rlocation("my_module/bar/runfile")).isNull();
+ assertThat(r.rlocation("my_workspace/bar/runfile")).isNull();
+ assertThat(r.rlocation("my_protobuf/foo/runfile")).isNull();
+ assertThat(r.rlocation("my_protobuf/bar/dir")).isNull();
+ assertThat(r.rlocation("my_protobuf/bar/dir/file")).isNull();
+ assertThat(r.rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le")).isNull();
+
+ assertThat(r.rlocation("protobuf/foo/runfile")).isNull();
+ assertThat(r.rlocation("protobuf/bar/dir")).isNull();
+ assertThat(r.rlocation("protobuf/bar/dir/file")).isNull();
+ assertThat(r.rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi~le")).isNull();
+
+ assertThat(r.rlocation("_main/bar/runfile")).isEqualTo(
+ "/the/path/./to/other//other runfile.txt");
+ assertThat(r.rlocation("protobuf~3.19.2/foo/runfile")).isEqualTo(
+ "C:/Actual Path\\protobuf\\runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir")).isEqualTo("E:\\Actual Path\\Directory");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/file")).isEqualTo(
+ "E:\\Actual Path\\Directory/file");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ "E:\\Actual Path\\Directory/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("config.json")).isEqualTo("/etc/config.json");
+ assertThat(r.rlocation("_main")).isNull();
+ assertThat(r.rlocation("my_module")).isNull();
+ assertThat(r.rlocation("protobuf")).isNull();
+ }
+
+ @Test
+ public void testManifestBasedRlocationWithRepoMapping_fromOtherRepo() throws Exception {
+ Path rm = tempFile("foo.repo_mapping", ImmutableList.of(
+ ",my_module,_main",
+ ",my_protobuf,protobuf~3.19.2",
+ ",my_workspace,_main",
+ "protobuf~3.19.2,protobuf,protobuf~3.19.2"));
+ Path mf = tempFile("foo.runfiles/MANIFEST", ImmutableList.of(
+ "_repo_mapping " + rm,
+ "config.json /etc/config.json",
+ "protobuf~3.19.2/foo/runfile C:/Actual Path\\protobuf\\runfile",
+ "_main/bar/runfile /the/path/./to/other//other runfile.txt",
+ "protobuf~3.19.2/bar/dir E:\\Actual Path\\Directory"));
+ Runfiles r = Runfiles.createManifestBasedForTesting(mf.toString())
+ .withSourceRepository("protobuf~3.19.2");
+
+ assertThat(r.rlocation("protobuf/foo/runfile")).isEqualTo("C:/Actual Path\\protobuf\\runfile");
+ assertThat(r.rlocation("protobuf/bar/dir")).isEqualTo("E:\\Actual Path\\Directory");
+ assertThat(r.rlocation("protobuf/bar/dir/file")).isEqualTo("E:\\Actual Path\\Directory/file");
+ assertThat(r.rlocation("protobuf/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ "E:\\Actual Path\\Directory/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("my_module/bar/runfile")).isNull();
+ assertThat(r.rlocation("my_protobuf/foo/runfile")).isNull();
+ assertThat(r.rlocation("my_protobuf/bar/dir")).isNull();
+ assertThat(r.rlocation("my_protobuf/bar/dir/file")).isNull();
+ assertThat(r.rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le")).isNull();
+
+ assertThat(r.rlocation("_main/bar/runfile")).isEqualTo(
+ "/the/path/./to/other//other runfile.txt");
+ assertThat(r.rlocation("protobuf~3.19.2/foo/runfile")).isEqualTo(
+ "C:/Actual Path\\protobuf\\runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir")).isEqualTo("E:\\Actual Path\\Directory");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/file")).isEqualTo(
+ "E:\\Actual Path\\Directory/file");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ "E:\\Actual Path\\Directory/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("config.json")).isEqualTo("/etc/config.json");
+ assertThat(r.rlocation("_main")).isNull();
+ assertThat(r.rlocation("my_module")).isNull();
+ assertThat(r.rlocation("protobuf")).isNull();
+ }
+
+ @Test
+ public void testDirectoryBasedRlocationWithRepoMapping_fromMain() throws Exception {
+ Path dir = tempDir.newFolder("foo.runfiles").toPath();
+ tempFile(dir.resolve("_repo_mapping").toString(), ImmutableList.of(
+ ",my_module,_main",
+ ",my_protobuf,protobuf~3.19.2",
+ ",my_workspace,_main",
+ "protobuf~3.19.2,protobuf,protobuf~3.19.2"));
+ Runfiles r = Runfiles.createDirectoryBasedForTesting(dir.toString()).withSourceRepository("");
+
+ assertThat(r.rlocation("my_module/bar/runfile")).isEqualTo(
+ dir + "/_main/bar/runfile");
+ assertThat(r.rlocation("my_workspace/bar/runfile")).isEqualTo(
+ dir + "/_main/bar/runfile");
+ assertThat(r.rlocation("my_protobuf/foo/runfile")).isEqualTo(
+ dir + "/protobuf~3.19.2/foo/runfile");
+ assertThat(r.rlocation("my_protobuf/bar/dir")).isEqualTo(dir + "/protobuf~3.19.2/bar/dir");
+ assertThat(r.rlocation("my_protobuf/bar/dir/file")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/file");
+ assertThat(r.rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("protobuf/foo/runfile")).isEqualTo(dir + "/protobuf/foo/runfile");
+ assertThat(r.rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/protobuf/bar/dir/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("_main/bar/runfile")).isEqualTo(
+ dir + "/_main/bar/runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/foo/runfile")).isEqualTo(
+ dir + "/protobuf~3.19.2/foo/runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir")).isEqualTo(dir + "/protobuf~3.19.2/bar/dir");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/file")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/file");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("config.json")).isEqualTo(dir + "/config.json");
+ }
+
+ @Test
+ public void testDirectoryBasedRlocationUnmapped() throws Exception {
+ Path dir = tempDir.newFolder("foo.runfiles").toPath();
+ Path rm = tempFile(dir.resolve("_repo_mapping").toString(), ImmutableList.of(
+ ",my_module,_main",
+ ",my_protobuf,protobuf~3.19.2",
+ ",my_workspace,_main",
+ "protobuf~3.19.2,protobuf,protobuf~3.19.2"));
+ Runfiles r = Runfiles.createDirectoryBasedForTesting(dir.toString()).unmapped();
+
+ assertThat(r.rlocation("my_module/bar/runfile")).isEqualTo(
+ dir + "/my_module/bar/runfile");
+ assertThat(r.rlocation("my_workspace/bar/runfile")).isEqualTo(
+ dir + "/my_workspace/bar/runfile");
+ assertThat(r.rlocation("my_protobuf/foo/runfile")).isEqualTo(
+ dir + "/my_protobuf/foo/runfile");
+ assertThat(r.rlocation("my_protobuf/bar/dir")).isEqualTo(dir + "/my_protobuf/bar/dir");
+ assertThat(r.rlocation("my_protobuf/bar/dir/file")).isEqualTo(
+ dir + "/my_protobuf/bar/dir/file");
+ assertThat(r.rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/my_protobuf/bar/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("protobuf/foo/runfile")).isEqualTo(dir + "/protobuf/foo/runfile");
+ assertThat(r.rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/protobuf/bar/dir/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("_main/bar/runfile")).isEqualTo(
+ dir + "/_main/bar/runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/foo/runfile")).isEqualTo(
+ dir + "/protobuf~3.19.2/foo/runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir")).isEqualTo(dir + "/protobuf~3.19.2/bar/dir");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/file")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/file");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("config.json")).isEqualTo(dir + "/config.json");
+ }
+
+ @Test
+ public void testDirectoryBasedRlocationWithRepoMapping_fromOtherRepo() throws Exception {
+ Path dir = tempDir.newFolder("foo.runfiles").toPath();
+ Path rm = tempFile(dir.resolve("_repo_mapping").toString(), ImmutableList.of(
+ ",my_module,_main",
+ ",my_protobuf,protobuf~3.19.2",
+ ",my_workspace,_main",
+ "protobuf~3.19.2,protobuf,protobuf~3.19.2"));
+ Runfiles r = Runfiles.createDirectoryBasedForTesting(dir.toString())
+ .withSourceRepository("protobuf~3.19.2");
+
+ assertThat(r.rlocation("protobuf/foo/runfile")).isEqualTo(dir + "/protobuf~3.19.2/foo/runfile");
+ assertThat(r.rlocation("protobuf/bar/dir")).isEqualTo(dir + "/protobuf~3.19.2/bar/dir");
+ assertThat(r.rlocation("protobuf/bar/dir/file")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/file");
+ assertThat(r.rlocation("protobuf/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("my_module/bar/runfile")).isEqualTo(dir + "/my_module/bar/runfile");
+ assertThat(r.rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/my_protobuf/bar/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("_main/bar/runfile")).isEqualTo(
+ dir + "/_main/bar/runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/foo/runfile")).isEqualTo(
+ dir + "/protobuf~3.19.2/foo/runfile");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir")).isEqualTo(dir + "/protobuf~3.19.2/bar/dir");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/file")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/file");
+ assertThat(r.rlocation("protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le")).isEqualTo(
+ dir + "/protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le");
+
+ assertThat(r.rlocation("config.json")).isEqualTo(dir + "/config.json");
+ }
+
+ @Test
+ public void testDirectoryBasedCtorArgumentValidation() throws IOException {
+ assertThrows(IllegalArgumentException.class,
+ () -> Runfiles.createDirectoryBasedForTesting(null).withSourceRepository(""));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> Runfiles.createDirectoryBasedForTesting("").withSourceRepository(""));
assertThrows(
IllegalArgumentException.class,
- () -> Runfiles.createDirectoryBasedForTesting("non-existent directory is bad"));
+ () -> Runfiles.createDirectoryBasedForTesting("non-existent directory is bad")
+ .withSourceRepository(""));
- Runfiles.createDirectoryBasedForTesting(System.getenv("TEST_TMPDIR"));
+ Runfiles.createDirectoryBasedForTesting(System.getenv("TEST_TMPDIR")).withSourceRepository("");
}
@Test
public void testManifestBasedCtorArgumentValidation() throws Exception {
assertThrows(
- IllegalArgumentException.class, () -> Runfiles.createManifestBasedForTesting(null));
+ IllegalArgumentException.class,
+ () -> Runfiles.createManifestBasedForTesting(null).withSourceRepository(""));
- assertThrows(IllegalArgumentException.class, () -> Runfiles.createManifestBasedForTesting(""));
+ assertThrows(IllegalArgumentException.class,
+ () -> Runfiles.createManifestBasedForTesting("").withSourceRepository(""));
- try (MockFile mf = new MockFile(ImmutableList.of("a b"))) {
- Runfiles.createManifestBasedForTesting(mf.path.toString());
- }
+ Path mf = tempFile("foobar", ImmutableList.of("a b"));
+ Runfiles.createManifestBasedForTesting(mf.toString()).withSourceRepository("");
+ }
+
+ @Test
+ public void testInvalidRepoMapping() throws Exception {
+ Path rm = tempFile("foo.repo_mapping", ImmutableList.of("a,b,c,d"));
+ Path mf = tempFile("foo.runfiles/MANIFEST", ImmutableList.of("_repo_mapping " + rm));
+ assertThrows(IllegalArgumentException.class,
+ () -> Runfiles.createManifestBasedForTesting(mf.toString()).withSourceRepository(""));
+ }
+
+ private Path tempFile(String path, ImmutableList lines) throws IOException {
+ Path file = tempDir.getRoot().toPath().resolve(path.replace('/', File.separatorChar));
+ Files.createDirectories(file.getParent());
+ return Files.write(file, lines, StandardCharsets.UTF_8);
}
}