// 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 java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * Runfiles lookup library for Bazel-built Java binaries and tests. * *
USAGE: * *
1. Depend on this runfiles library from your build rule: * *
* java_binary( * name = "my_binary", * ... * deps = ["@bazel_tools//tools/java/runfiles"], * ) ** *
2. Import the runfiles library. * *
* import com.google.devtools.build.runfiles.Runfiles; ** *
3. Create a Runfiles object and use rlocation to look up runfile paths: * *
* public void myFunction() { * Runfiles runfiles = Runfiles.create(); * String path = runfiles.rlocation("my_workspace/path/to/my/data.txt"); * ... ** *
If you want to start subprocesses that also need runfiles, you need to set the right * environment variables for them: * *
* String path = r.rlocation("path/to/binary"); * ProcessBuilder pb = new ProcessBuilder(path); * pb.environment().putAll(r.getEnvVars()); * ... * Process p = pb.start(); **/ public abstract class Runfiles { // Package-private constructor, so only package-private classes may extend it. private Runfiles() {} /** * Returns a new {@link Runfiles} instance. * *
This method passes the JVM's environment variable map to {@link #create(Map)}. */ public static Runfiles create() throws IOException { return create(System.getenv()); } /** * Returns a new {@link Runfiles} instance. * *
The returned object is either: * *
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
*/
public static Runfiles create(Map 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 "//")
*/
public final String rlocation(String path) {
Util.checkArgument(path != null);
Util.checkArgument(!path.isEmpty());
Util.checkArgument(
!path.startsWith("../")
&& !path.contains("/..")
&& !path.startsWith("./")
&& !path.contains("/./")
&& !path.endsWith("/.")
&& !path.contains("//"),
"path is not normalized: \"%s\"",
path);
Util.checkArgument(
!path.startsWith("\\"), "path is absolute without a drive letter: \"%s\"", path);
if (new File(path).isAbsolute()) {
return path;
}
return rlocationChecked(path);
}
/**
* Returns environment variables for subprocesses.
*
* 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