From 5025168d72cf1b63def7ff2ec375c164bda0b429 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Wed, 12 Aug 2026 22:50:43 +0200 Subject: [PATCH 1/3] Select the runfiles implementation based on the regular runfiles variables `RUNFILES_MANIFEST_ONLY` is derived from `--enable_runfiles`, an analysis-time flag, and thus doesn't account for the runfiles directory being materialized by the sandbox or by remote execution. When it is set but the runfiles directory has been materialized, no manifest has been staged and the library fails to initialize even though all runfiles are right there. Determine the implementation from the variables that name the two candidates instead, as all other runfiles libraries do: use the manifest if `RUNFILES_MANIFEST_FILE` names an existing file, otherwise use the runfiles directory if `RUNFILES_DIR` (or `JAVA_RUNFILES`) names an existing directory. Whoever sets up the environment already knows which of the two it staged and only names the one that is usable, so a value that names something that isn't there is dropped rather than trusted. Also pass the runfiles directory from the environment on to `getEnvVars` instead of always deriving it from the manifest path, which only works if the two are adjacent. --- .../devtools/build/runfiles/Runfiles.java | 105 ++++++++---------- .../devtools/build/runfiles/RunfilesTest.java | 86 ++++++++++---- 2 files changed, 113 insertions(+), 78 deletions(-) diff --git a/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java b/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java index 06221b76..2cf90f42 100644 --- a/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java +++ b/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java @@ -248,30 +248,49 @@ public static synchronized Preloaded preload() throws IOException { *
  • 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}. + *

    If {@code env} contains "RUNFILES_MANIFEST_FILE" and it points to an existing file, this + * method returns a manifest-based implementation backed by that file. * - *

    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. + *

    Otherwise, if {@code env} contains "RUNFILES_DIR" (or, if absent, "JAVA_RUNFILES") and it + * points to an existing directory, this method returns a directory-based implementation backed by + * that directory. * *

    Note about performance: the manifest-based implementation eagerly reads and caches the whole * manifest file upon instantiation. * - * @throws java.io.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 + * @throws java.io.IOException if neither a runfiles manifest nor a runfiles directory could be + * found, or some IO error occurs */ 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 - // faster to use RUNFILES_DIR. - return new ManifestBased(getManifestPath(env)); - } else { - return new DirectoryBased(getRunfilesDir(env)); + // A manifest and a directory may both be named: the process that set up the environment knows + // which of the two it staged, and communicates that by only naming the one that is usable. + // Values that name something that isn't there are dropped rather than trusted, since a launcher + // or parent process may have derived them from a build-time flag that doesn't account for the + // runfiles directory having been materialized by the sandbox or by remote execution. + String manifestPathValue = env.get("RUNFILES_MANIFEST_FILE"); + String runfilesDirValue = env.get("RUNFILES_DIR"); + if (Util.isNullOrEmpty(runfilesDirValue)) { + // The java_binary launcher script only exports JAVA_RUNFILES, so for a process it starts, + // this is the only variable that names the runfiles directory. + runfilesDirValue = env.get("JAVA_RUNFILES"); } + + boolean hasManifest = + !Util.isNullOrEmpty(manifestPathValue) && new File(manifestPathValue).isFile(); + boolean hasDirectory = + !Util.isNullOrEmpty(runfilesDirValue) && new File(runfilesDirValue).isDirectory(); + + if (hasManifest) { + return new ManifestBased(manifestPathValue, hasDirectory ? runfilesDirValue : null); + } + if (hasDirectory) { + return new DirectoryBased(runfilesDirValue); + } + throw new IOException( + String.format( + "Cannot find runfiles: $RUNFILES_MANIFEST_FILE (%s) does not name an existing file and" + + " $RUNFILES_DIR / $JAVA_RUNFILES (%s) does not name an existing directory", + manifestPathValue, runfilesDirValue)); } /** @@ -297,20 +316,13 @@ public static Runfiles create() throws IOException { *

  • 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. + *

    See {@link #preload(java.util.Map)} for how the implementation is chosen. * *

    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 + * @throws IOException if neither a runfiles manifest nor a runfiles directory could be found, or + * some IO error occurs * @deprecated Use {@link #preload(java.util.Map)} instead. With {@code --enable_bzlmod}, this * function does not work correctly. */ @@ -380,44 +392,20 @@ String getCanonicalRepositoryName(String apparentRepositoryName) { apparentRepositoryName); } - /** Returns true if the platform supports runfiles only via manifests. */ - private static boolean isManifestOnly(Map env) { - return "1".equals(env.get("RUNFILES_MANIFEST_ONLY")); - } - - private static String getManifestPath(Map env) throws IOException { - String value = env.get("RUNFILES_MANIFEST_FILE"); - if (Util.isNullOrEmpty(value)) { - throw new IOException( - "Cannot load runfiles manifest: $RUNFILES_MANIFEST_ONLY is 1 but" - + " $RUNFILES_MANIFEST_FILE is empty or undefined"); - } - return value; - } - - private static String getRunfilesDir(Map env) throws IOException { - String value = env.get("RUNFILES_DIR"); - if (Util.isNullOrEmpty(value)) { - value = env.get("JAVA_RUNFILES"); - } - if (Util.isNullOrEmpty(value)) { - throw new IOException( - "Cannot find runfiles: $RUNFILES_DIR and $JAVA_RUNFILES are both unset or empty"); - } - return value; - } - /** {@link Runfiles} implementation that parses a runfiles-manifest file to look up runfiles. */ private static final class ManifestBased extends Preloaded { private final Map runfiles; private final String manifestPath; + private final String runfilesDir; private final RepositoryMapping repoMapping; - ManifestBased(String manifestPath) throws IOException { + ManifestBased(String manifestPath, String runfilesDir) throws IOException { Util.checkArgument(manifestPath != null); Util.checkArgument(!manifestPath.isEmpty()); this.manifestPath = manifestPath; + this.runfilesDir = + Util.isNullOrEmpty(runfilesDir) ? findRunfilesDir(manifestPath) : runfilesDir; this.runfiles = loadRunfiles(manifestPath); this.repoMapping = RepositoryMapping.readFromFile(rlocationChecked("_repo_mapping")); } @@ -444,9 +432,12 @@ protected String rlocationChecked(String path) { @Override protected Map getEnvVars() { HashMap result = new HashMap<>(4); - result.put("RUNFILES_MANIFEST_ONLY", "1"); result.put("RUNFILES_MANIFEST_FILE", manifestPath); - String runfilesDir = findRunfilesDir(manifestPath); + // Runfiles libraries that decide between the two implementations based on this variable + // instead of on which of the other two names an existing path need it to use the manifest. + result.put("RUNFILES_MANIFEST_ONLY", "1"); + // The runfiles directory is not fully materialized in this case, but language launchers locate + // their own runtime data relative to it, so pass it on if it is known. result.put("RUNFILES_DIR", runfilesDir); // TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can pick up RUNFILES_DIR. result.put("JAVA_RUNFILES", runfilesDir); @@ -546,7 +537,7 @@ protected Map getEnvVars() { } static Preloaded createManifestBasedForTesting(String manifestPath) throws IOException { - return new ManifestBased(manifestPath); + return new ManifestBased(manifestPath, /* runfilesDir= */ null); } static Preloaded createDirectoryBasedForTesting(String runfilesDir) throws IOException { diff --git a/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java b/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java index 406ebe8f..0b2c4d15 100644 --- a/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java +++ b/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java @@ -76,12 +76,17 @@ public void testRlocationArgumentValidation() throws Exception { @Test public void testCreatesManifestBasedRunfiles() throws Exception { Path mf = tempFile("foo.runfiles_manifest", ImmutableList.of("a/b c/d")); + Path dir = + Files.createTempDirectory( + FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); + + // The manifest takes precedence over the runfiles directory: whoever set up the environment + // only names the manifest if the runfiles directory hasn't been fully materialized. Runfiles r = Runfiles.create( ImmutableMap.of( - "RUNFILES_MANIFEST_ONLY", "1", "RUNFILES_MANIFEST_FILE", mf.toString(), - "RUNFILES_DIR", "ignored when RUNFILES_MANIFEST_ONLY=1", + "RUNFILES_DIR", dir.toString(), "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value", "TEST_SRCDIR", "should always be ignored")); assertThat(r.rlocation("a/b")).isEqualTo("c/d"); @@ -95,6 +100,19 @@ public void testCreatesManifestBasedRunfiles() throws Exception { } } + @Test + public void testCreatesManifestBasedRunfilesWithoutManifestOnly() throws Exception { + // RUNFILES_MANIFEST_ONLY is not consulted: it is derived from --enable_runfiles at analysis + // time, which doesn't account for how the runfiles were staged for this particular process. + Path mf = tempFile("foo.runfiles_manifest", ImmutableList.of("a/b c/d")); + Runfiles r = + Runfiles.create( + ImmutableMap.of( + "RUNFILES_MANIFEST_ONLY", "", + "RUNFILES_MANIFEST_FILE", mf.toString())); + assertThat(r.rlocation("a/b")).isEqualTo("c/d"); + } + @Test public void testCreatesDirectoryBasedRunfiles() throws Exception { Path dir = @@ -104,7 +122,6 @@ public void testCreatesDirectoryBasedRunfiles() throws Exception { Runfiles r = Runfiles.create( ImmutableMap.of( - "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "RUNFILES_DIR", dir.toString(), "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value", "TEST_SRCDIR", "should always be ignored")); @@ -114,7 +131,6 @@ public void testCreatesDirectoryBasedRunfiles() throws Exception { r = Runfiles.create( ImmutableMap.of( - "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "RUNFILES_DIR", "", "JAVA_RUNFILES", dir.toString(), "TEST_SRCDIR", "should always be ignored")); @@ -122,6 +138,23 @@ public void testCreatesDirectoryBasedRunfiles() throws Exception { assertThat(r.rlocation("foo")).endsWith("/foo"); } + @Test + public void testCreatesDirectoryBasedRunfilesWithMissingManifest() throws Exception { + // The sandbox and remote execution materialize the runfiles directory without staging the + // manifest, even though a launcher or parent process may have named one. + Path dir = + Files.createTempDirectory( + FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); + + Runfiles r = + Runfiles.create( + ImmutableMap.of( + "RUNFILES_MANIFEST_ONLY", "1", + "RUNFILES_MANIFEST_FILE", dir.resolve("MANIFEST").toString(), + "RUNFILES_DIR", dir.toString())); + assertThat(r.rlocation("a/b")).isEqualTo(dir + "/a/b"); + } + @Test public void testIgnoresTestSrcdirWhenJavaRunfilesIsUndefinedAndJustFails() throws Exception { Path dir = @@ -131,13 +164,11 @@ public void testIgnoresTestSrcdirWhenJavaRunfilesIsUndefinedAndJustFails() throw Runfiles.create( ImmutableMap.of( "RUNFILES_DIR", dir.toString(), - "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "TEST_SRCDIR", "should always be ignored")); Runfiles.create( ImmutableMap.of( "JAVA_RUNFILES", dir.toString(), - "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "TEST_SRCDIR", "should always be ignored")); IOException e = @@ -150,24 +181,23 @@ public void testIgnoresTestSrcdirWhenJavaRunfilesIsUndefinedAndJustFails() throw "", "JAVA_RUNFILES", "", - "RUNFILES_MANIFEST_FILE", - "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"); + assertThat(e).hasMessageThat().contains("$RUNFILES_DIR / $JAVA_RUNFILES"); } @Test - public void testFailsToCreateManifestBasedBecauseManifestDoesNotExist() { + public void testFailsToCreateBecauseNeitherManifestNorDirectoryExists() { IOException e = assertThrows( IOException.class, () -> Runfiles.create( ImmutableMap.of( - "RUNFILES_MANIFEST_ONLY", "1", - "RUNFILES_MANIFEST_FILE", "non-existing path"))); - assertThat(e).hasMessageThat().contains("non-existing path"); + "RUNFILES_MANIFEST_FILE", "non-existing manifest", + "RUNFILES_DIR", "non-existing directory"))); + assertThat(e).hasMessageThat().contains("non-existing manifest"); + assertThat(e).hasMessageThat().contains("non-existing directory"); } @Test @@ -176,15 +206,14 @@ public void testManifestBasedEnvVars() throws Exception { Map envvars = 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")) .getEnvVars(); assertThat(envvars.keySet()) .containsExactly( "RUNFILES_MANIFEST_ONLY", "RUNFILES_MANIFEST_FILE", "RUNFILES_DIR", "JAVA_RUNFILES"); + // Subprocesses that don't check whether the runfiles directory has been materialized rely on + // RUNFILES_MANIFEST_ONLY to make them use the manifest. assertThat(envvars.get("RUNFILES_MANIFEST_ONLY")).isEqualTo("1"); assertThat(envvars.get("RUNFILES_MANIFEST_FILE")).isEqualTo(mf.toString()); assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(tempDir.getRoot().toString()); @@ -196,10 +225,7 @@ public void testManifestBasedEnvVars() throws Exception { envvars = 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")) .getEnvVars(); assertThat(envvars.get("RUNFILES_MANIFEST_ONLY")).isEqualTo("1"); @@ -208,13 +234,31 @@ public void testManifestBasedEnvVars() throws Exception { assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(rfDir.toString()); } + @Test + public void testManifestBasedEnvVarsPassOnTheRunfilesDirectoryFromTheEnvironment() + throws Exception { + // The runfiles directory doesn't have to be adjacent to the manifest, in which case it can only + // be taken from the environment. + Path mf = tempFile("manifest_with_unrelated_name", ImmutableList.of()); + Path dir = + Files.createTempDirectory( + FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); + + Map envvars = + Runfiles.create( + ImmutableMap.of( + "RUNFILES_MANIFEST_FILE", mf.toString(), + "RUNFILES_DIR", dir.toString())) + .getEnvVars(); + assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(dir.toString()); + assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(dir.toString()); + } + @Test public void testDirectoryBasedEnvVars() throws Exception { Map envvars = Runfiles.create( ImmutableMap.of( - "RUNFILES_MANIFEST_FILE", - "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "RUNFILES_DIR", tempDir.getRoot().toString(), "JAVA_RUNFILES", From 1ea065f0a874dbc759e893630e7bd022f54b2263 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Wed, 12 Aug 2026 22:51:12 +0200 Subject: [PATCH 2/3] Clear the manifest variables in `getEnvVars` if the runfiles directory is used A subprocess that inherits `RUNFILES_MANIFEST_FILE` or `RUNFILES_MANIFEST_ONLY` from an ancestor process resolves its runfiles through a manifest that describes how that process' runfiles were staged, not how the current process' runfiles were, and thus disagrees with the runfiles directory passed to it in `RUNFILES_DIR`. Set both variables to the empty string, which every runfiles library treats as unset, so that the implementation this process selected is also the one its subprocesses select. --- .../java/com/google/devtools/build/runfiles/Runfiles.java | 7 ++++++- .../com/google/devtools/build/runfiles/RunfilesTest.java | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java b/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java index 2cf90f42..8262ccf9 100644 --- a/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java +++ b/java/runfiles/src/main/java/com/google/devtools/build/runfiles/Runfiles.java @@ -528,10 +528,15 @@ protected RepositoryMapping getRepoMapping() { @Override protected Map getEnvVars() { - HashMap result = new HashMap<>(2); + HashMap result = new HashMap<>(4); result.put("RUNFILES_DIR", runfilesRoot); // TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can pick up RUNFILES_DIR. result.put("JAVA_RUNFILES", runfilesRoot); + // Clear values inherited from an ancestor process, which describe how that process' runfiles + // were staged and not how this process' runfiles were. Since the variables are set to the + // empty string rather than to a path, a subprocess that doesn't recognize them is unaffected. + result.put("RUNFILES_MANIFEST_FILE", ""); + result.put("RUNFILES_MANIFEST_ONLY", ""); return result; } } diff --git a/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java b/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java index 0b2c4d15..86b17866 100644 --- a/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java +++ b/test/java/runfiles/src/test/java/com/google/devtools/build/runfiles/RunfilesTest.java @@ -266,9 +266,15 @@ public void testDirectoryBasedEnvVars() throws Exception { "TEST_SRCDIR", "should always be ignored")) .getEnvVars(); - assertThat(envvars.keySet()).containsExactly("RUNFILES_DIR", "JAVA_RUNFILES"); + assertThat(envvars.keySet()) + .containsExactly( + "RUNFILES_DIR", "JAVA_RUNFILES", "RUNFILES_MANIFEST_FILE", "RUNFILES_MANIFEST_ONLY"); assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(tempDir.getRoot().toString()); assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(tempDir.getRoot().toString()); + // Values inherited from an ancestor process must not make a subprocess use a manifest instead + // of the fully materialized runfiles directory. + assertThat(envvars.get("RUNFILES_MANIFEST_FILE")).isEmpty(); + assertThat(envvars.get("RUNFILES_MANIFEST_ONLY")).isEmpty(); } @Test From 07eb555f59119500f6a49eac9afb682fdf93ac5d Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Wed, 12 Aug 2026 22:51:21 +0200 Subject: [PATCH 3/3] Export the regular runfiles variables from the `java_binary` launcher The launcher script exports `JAVA_RUNFILES`, but not `RUNFILES_DIR`, so a subprocess whose runfiles library only knows about the latter can't find the runfiles directory. It also exports `RUNFILES_MANIFEST_FILE` and `RUNFILES_MANIFEST_ONLY` based on `--enable_runfiles` alone, which tells subprocesses to use a manifest that hasn't been staged whenever the sandbox or remote execution materialized the runfiles directory instead. This makes a `java_binary` used as a tool fail with `--noenable_runfiles`, since even its own `rlocation` can't resolve the JVM launcher. Export `RUNFILES_DIR` alongside `JAVA_RUNFILES`, and only point subprocesses at the manifest if it has actually been staged. `rlocation` now resolves against the runfiles directory in that case, which is what it already did whenever runfiles were enabled. --- java/bazel/rules/java_stub_template.txt | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/java/bazel/rules/java_stub_template.txt b/java/bazel/rules/java_stub_template.txt index 8dddd4a3..23dbe2a1 100644 --- a/java/bazel/rules/java_stub_template.txt +++ b/java/bazel/rules/java_stub_template.txt @@ -193,15 +193,26 @@ if is_windows; then fi export JAVA_RUNFILES -export RUNFILES_MANIFEST_FILE="${JAVA_RUNFILES}/MANIFEST" -export RUNFILES_MANIFEST_ONLY=%runfiles_manifest_only% +# Runfiles libraries look up the runfiles directory in RUNFILES_DIR; JAVA_RUNFILES is only still +# exported for the benefit of this script and of tools that predate RUNFILES_DIR. +export RUNFILES_DIR="$JAVA_RUNFILES" +# %runfiles_manifest_only% is derived from --enable_runfiles, which doesn't account for the runfiles +# directory being materialized by the sandbox or by remote execution. Only ask subprocesses to use +# the manifest if it has actually been staged, and tell them to use the runfiles directory otherwise. +if [[ "%runfiles_manifest_only%" == 1 && -e "${JAVA_RUNFILES}/MANIFEST" ]]; then + export RUNFILES_MANIFEST_FILE="${JAVA_RUNFILES}/MANIFEST" + export RUNFILES_MANIFEST_ONLY=1 +else + export RUNFILES_MANIFEST_FILE= + export RUNFILES_MANIFEST_ONLY= +fi if [ -z "$RUNFILES_MANIFEST_ONLY" ]; then function rlocation() { if [[ "$1" = /* ]]; then echo $1 else - echo "$(dirname $RUNFILES_MANIFEST_FILE)/$1" + echo "${JAVA_RUNFILES}/$1" fi } else