diff options
author | kchodorow <kchodorow@google.com> | 2017-04-19 18:58:50 +0200 |
---|---|---|
committer | Klaus Aehlig <aehlig@google.com> | 2017-04-20 11:06:33 +0200 |
commit | dfcd5da86e2acfd42ca09c7f65e012465ab3e382 (patch) | |
tree | c97a59df14ca5e7c3953b4fac038c09b2033d207 /src/main/java/com/google/devtools/build/lib/rules/repository | |
parent | ac64fd7b27ca511738801b7ac2dbb9439615183b (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')
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); |