aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/repository
diff options
context:
space:
mode:
authorGravatar kchodorow <kchodorow@google.com>2017-04-19 18:58:50 +0200
committerGravatar Klaus Aehlig <aehlig@google.com>2017-04-20 11:06:33 +0200
commitdfcd5da86e2acfd42ca09c7f65e012465ab3e382 (patch)
treec97a59df14ca5e7c3953b4fac038c09b2033d207 /src/main/java/com/google/devtools/build/lib/rules/repository
parentac64fd7b27ca511738801b7ac2dbb9439615183b (diff)
Add repository override option
RELNOTES: Adds a --override_repository option that takes a repository name and path. This forces Bazel to use the directory at that path for the repository. Example usage: `--override_repository=foo=/home/user/gitroot/foo`. Fixes #1266 PiperOrigin-RevId: 153599291
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/repository')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java56
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java9
3 files changed, 60 insertions, 21 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
index ee387f735d..916569c4cb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
@@ -40,14 +40,20 @@ public class LocalRepositoryFunction extends RepositoryFunction {
BlazeDirectories directories, Environment env, Map<String, String> markerData)
throws InterruptedException, RepositoryFunctionException {
PathFragment pathFragment = RepositoryFunction.getTargetPath(rule, directories.getWorkspace());
+ return LocalRepositoryFunction.symlink(outputDirectory, pathFragment, env);
+ }
+
+ public static RepositoryDirectoryValue.Builder symlink(
+ Path source, PathFragment destination, Environment env)
+ throws RepositoryFunctionException, InterruptedException {
try {
- outputDirectory.createSymbolicLink(pathFragment);
+ source.createSymbolicLink(destination);
} catch (IOException e) {
throw new RepositoryFunctionException(
- new IOException("Could not create symlink to repository " + pathFragment + ": "
+ new IOException("Could not create symlink to repository " + destination + ": "
+ e.getMessage(), e), Transience.TRANSIENT);
}
- FileValue repositoryValue = getRepositoryDirectory(outputDirectory, env);
+ FileValue repositoryValue = getRepositoryDirectory(source, env);
if (repositoryValue == null) {
// TODO(bazel-team): If this returns null, we unnecessarily recreate the symlink above on the
// second execution.
@@ -56,10 +62,10 @@ public class LocalRepositoryFunction extends RepositoryFunction {
if (!repositoryValue.isDirectory()) {
throw new RepositoryFunctionException(
- new IOException(rule + " must specify an existing directory"), Transience.TRANSIENT);
+ new IOException(source + " must be an existing directory"), Transience.TRANSIENT);
}
- return RepositoryDirectoryValue.builder().setPath(outputDirectory);
+ return RepositoryDirectoryValue.builder().setPath(source);
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
index 771231b72b..259950beda 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
@@ -25,10 +25,13 @@ import com.google.devtools.build.lib.packages.RuleFormatter;
import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
import com.google.devtools.build.lib.skyframe.FileValue;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
+import com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed;
+import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
@@ -49,6 +52,8 @@ import javax.annotation.Nullable;
* this function.
*/
public final class RepositoryDelegatorFunction implements SkyFunction {
+ public static final Precomputed<Map<RepositoryName, PathFragment>> REPOSITORY_OVERRIDES =
+ new Precomputed<>(SkyKey.create(SkyFunctions.PRECOMPUTED, "repository_overrides"));
// The marker file version is inject in the rule key digest so the rule key is always different
// when we decide to update the format.
@@ -93,13 +98,22 @@ public final class RepositoryDelegatorFunction implements SkyFunction {
public SkyValue compute(SkyKey skyKey, Environment env)
throws SkyFunctionException, InterruptedException {
RepositoryName repositoryName = (RepositoryName) skyKey.argument();
- Rule rule = RepositoryFunction.getRule(repositoryName, null, env);
- if (rule == null) {
+ BlazeDirectories directories = PrecomputedValue.BLAZE_DIRECTORIES.get(env);
+ Map<RepositoryName, PathFragment> overrides = REPOSITORY_OVERRIDES.get(env);
+ if (env.valuesMissing()) {
return null;
}
- BlazeDirectories directories = PrecomputedValue.BLAZE_DIRECTORIES.get(env);
- if (directories == null) {
+ Path repoRoot = RepositoryFunction.getExternalRepositoryDirectory(directories)
+ .getRelative(repositoryName.strippedName());
+ Path markerPath = getMarkerPath(directories, repositoryName.strippedName());
+ if (overrides.containsKey(repositoryName)) {
+ return setupOverride(
+ repositoryName, overrides.get(repositoryName), env, repoRoot, markerPath);
+ }
+
+ Rule rule = RepositoryFunction.getRule(repositoryName, null, env);
+ if (rule == null) {
return null;
}
RepositoryFunction handler;
@@ -110,23 +124,20 @@ public final class RepositoryDelegatorFunction implements SkyFunction {
}
if (handler == null) {
throw new RepositoryFunctionException(
- new EvalException(Location.fromFile(directories.getWorkspace().getRelative("WORKSPACE")),
+ new EvalException(
+ Location.fromFile(directories.getWorkspace().getRelative("WORKSPACE")),
"Could not find handler for " + rule),
Transience.PERSISTENT);
}
handler.setClientEnvironment(clientEnvironment);
- Path repoRoot =
- RepositoryFunction.getExternalRepositoryDirectory(directories).getRelative(rule.getName());
byte[] ruleSpecificData = handler.getRuleSpecificMarkerData(rule, env);
if (ruleSpecificData == null) {
return null;
}
String ruleKey = computeRuleKey(rule, ruleSpecificData);
Map<String, String> markerData = new TreeMap<>();
- Path markerPath = getMarkerPath(directories, rule);
-
if (handler.isLocal(rule)) {
// Local repositories are always fetched because the operation is generally fast and they do
// not depend on non-local data, so it does not make much sense to try to cache from across
@@ -207,7 +218,7 @@ public final class RepositoryDelegatorFunction implements SkyFunction {
.setFetchingDelayed().build();
}
- private final String computeRuleKey(Rule rule, byte[] ruleSpecificData) {
+ private String computeRuleKey(Rule rule, byte[] ruleSpecificData) {
return new Fingerprint().addBytes(RuleFormatter.serializeRule(rule).build().toByteArray())
.addBytes(ruleSpecificData)
.addInt(MARKER_FILE_VERSION).hexDigestAndReset();
@@ -226,7 +237,7 @@ public final class RepositoryDelegatorFunction implements SkyFunction {
* system is up to date.
*/
@Nullable
- private final byte[] isFilesystemUpToDate(Path markerPath, Rule rule, String ruleKey,
+ private byte[] isFilesystemUpToDate(Path markerPath, Rule rule, String ruleKey,
RepositoryFunction handler, Environment env)
throws RepositoryFunctionException, InterruptedException {
try {
@@ -310,7 +321,7 @@ public final class RepositoryDelegatorFunction implements SkyFunction {
return result.toString();
}
- private final byte[] writeMarkerFile(
+ private byte[] writeMarkerFile(
Path markerPath, Map<String, String> markerData, String ruleKey)
throws RepositoryFunctionException {
try {
@@ -329,13 +340,30 @@ public final class RepositoryDelegatorFunction implements SkyFunction {
}
}
- private static Path getMarkerPath(BlazeDirectories directories, Rule rule) {
+ private static Path getMarkerPath(BlazeDirectories directories, String ruleName) {
return RepositoryFunction.getExternalRepositoryDirectory(directories)
- .getChild("@" + rule.getName() + ".marker");
+ .getChild("@" + ruleName + ".marker");
}
@Override
public String extractTag(SkyKey skyKey) {
return null;
}
+
+ private RepositoryDirectoryValue setupOverride(
+ RepositoryName repositoryName, PathFragment sourcePath, Environment env, Path repoRoot,
+ Path markerPath)
+ throws RepositoryFunctionException, InterruptedException {
+ setupRepositoryRoot(repoRoot);
+ RepositoryDirectoryValue.Builder directoryValue = LocalRepositoryFunction.symlink(
+ repoRoot, sourcePath, env);
+ if (directoryValue == null) {
+ return null;
+ }
+ String ruleKey = new Fingerprint().addBytes(repositoryName.strippedName().getBytes())
+ .addBytes(repoRoot.getFileSystem().getPath(sourcePath).getPathString().getBytes())
+ .addInt(MARKER_FILE_VERSION).hexDigestAndReset();
+ byte[] digest = writeMarkerFile(markerPath, new TreeMap<String, String>(), ruleKey);
+ return directoryValue.setDigest(digest).build();
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
index 51486eda50..8afb6eeb83 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
@@ -470,7 +470,12 @@ public abstract class RepositoryFunction {
// function so we get invalidation when the repository is fetched.
// For the repository directory itself, we cannot depends on the RepositoryDirectoryValue
// (cycle).
- env.getValue(RepositoryDirectoryValue.key(RepositoryName.create("@" + repositoryName)));
+ env.getValue(
+ RepositoryDirectoryValue.key(
+ RepositoryName.createFromValidStrippedName(repositoryName)));
+ } else {
+ // Invalidate external/<repo> if the repository overrides change.
+ RepositoryDelegatorFunction.REPOSITORY_OVERRIDES.get(env);
}
} catch (RepositoryFunction.RepositoryNotFoundException ex) {
// The repository we are looking for does not exist so we should depend on the whole
@@ -478,7 +483,7 @@ public abstract class RepositoryFunction {
// already requested all repository functions from the WORKSPACE file from Skyframe as part
// of the resolution. Therefore we are safe to ignore that Exception.
return;
- } catch (RepositoryFunctionException | LabelSyntaxException ex) {
+ } catch (RepositoryFunctionException ex) {
// This should never happen.
throw new IllegalStateException(
"Repository " + repositoryName + " cannot be resolved for path " + rootedPath, ex);