aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com
diff options
context:
space:
mode:
authorGravatar dannark <dannark@google.com>2018-06-04 13:53:22 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-06-04 13:54:52 -0700
commitc3495858f097451e06044778bc806e94e06d6da7 (patch)
tree6350516aaddd9bf93643c86d936a92fc9256d385 /src/main/java/com
parentba25d49ce2c6bb86e93e19cfe9bb8da1399a3c43 (diff)
Process 'repo_mapping' attribute from WORKSPACE rules. 'repo_mapping' is a way to remap references to repositories within an external repository by another name. This CL only adds the mappings to the Package object, but it does not actually enable the reassignments.
Example usage (in a WORKSPACE file): local_repository( name = ?a?, path = ?../a?, repo_mapping = {?@x? : ?@y?} ) This change also creates a new SkyKey which represents the mappings. This is to prevent all packages from depending on the external package, and instead depending just on the mappings. i.e. a change to the WORKSPACE file that does not touch the mappings shouldn't cause a reload of the package. RELNOTES:None PiperOrigin-RevId: 199187963
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/Package.java123
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java35
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java35
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java63
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java110
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java2
9 files changed, 367 insertions, 16 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java
index 7e15bd2b42..f0f79d4d7e 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Package.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java
@@ -25,6 +25,7 @@ import com.google.common.collect.Lists;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.collect.CollectionUtils;
import com.google.devtools.build.lib.collect.ImmutableSortedKeyMap;
import com.google.devtools.build.lib.events.Event;
@@ -180,6 +181,20 @@ public class Package {
private License defaultLicense;
private Set<License.DistributionType> defaultDistributionSet;
+ /**
+ * The map from each repository to that repository's remappings map.
+ * This is only used in the //external package, it is an empty map for all other packages.
+ * For example, an entry of {"@foo" : {"@x", "@y"}} indicates that, within repository foo,
+ * "@x" should be remapped to "@y".
+ */
+ private ImmutableMap<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>>
+ externalPackageRepositoryMappings;
+
+ /**
+ * The map of repository reassignments for BUILD packages. This will be empty for packages
+ * within the main workspace.
+ */
+ private ImmutableMap<RepositoryName, RepositoryName> repositoryMapping;
/**
* The names of the package() attributes that declare default values for rule
@@ -225,6 +240,49 @@ public class Package {
}
/**
+ * Returns the repository mapping for the requested external repository.
+ *
+ * @throws UnsupportedOperationException if called from a package other than
+ * the //external package
+ */
+ public ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping(
+ RepositoryName repository) {
+ if (!isWorkspace()) {
+ throw new UnsupportedOperationException("Can only access the external package repository"
+ + "mappings from the //external package");
+ }
+ return externalPackageRepositoryMappings.getOrDefault(repository, ImmutableMap.of());
+ }
+
+ /**
+ * Returns the workspace mappings for the repository with the given absolute name.
+ *
+ * @throws LabelSyntaxException if repository is not a valid {@link RepositoryName}
+ */
+ public ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping(
+ String repository) throws LabelSyntaxException {
+ RepositoryName repositoryName = RepositoryName.create(repository);
+ return getRepositoryMapping(repositoryName);
+ }
+
+ /**
+ * Gets the global name for a repository within an external repository.
+ *
+ * <p>{@code localName} is a repository name reference found in a BUILD file within a repository
+ * external to the main workspace. This method returns the main workspace's global remapped name
+ * for {@code localName}.
+ */
+ public RepositoryName getGlobalName(RepositoryName localName) {
+ RepositoryName globalname = repositoryMapping.get(localName);
+ return globalname != null ? globalname : localName;
+ }
+
+ /** Returns whether we are in the WORKSPACE file or not. */
+ public boolean isWorkspace() {
+ return getPackageIdentifier().equals(Label.EXTERNAL_PACKAGE_IDENTIFIER);
+ }
+
+ /**
* Package initialization: part 2 of 3: sets this package's default header
* strictness checking.
*
@@ -335,6 +393,20 @@ public class Package {
this.posts = ImmutableList.copyOf(builder.posts);
this.registeredExecutionPlatforms = ImmutableList.copyOf(builder.registeredExecutionPlatforms);
this.registeredToolchains = ImmutableList.copyOf(builder.registeredToolchains);
+ this.repositoryMapping = builder.repositoryMapping;
+ ImmutableMap.Builder<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>>
+ repositoryMappingsBuilder = ImmutableMap.builder();
+ if (!builder.externalPackageRepositoryMappings.isEmpty() && !builder.isWorkspace()) {
+ // 'repo_mapping' should only be used in the //external package, i.e. should only appear
+ // in WORKSPACE files. Currently, if someone tries to use 'repo_mapping' in a BUILD rule, they
+ // will get a "no such attribute" error. This check is to protect against a 'repo_mapping'
+ // attribute being added to a rule in the future.
+ throw new IllegalArgumentException(
+ "'repo_mapping' may only be used in the //external package");
+ }
+ builder.externalPackageRepositoryMappings.forEach((k, v) ->
+ repositoryMappingsBuilder.put(k, ImmutableMap.copyOf(v)));
+ this.externalPackageRepositoryMappings = repositoryMappingsBuilder.build();
}
/**
@@ -729,6 +801,13 @@ public class Package {
*/
protected Package pkg;
+ // The map from each repository to that repository's remappings map.
+ // This is only used in the //external package, it is an empty map for all other packages.
+ private final HashMap<RepositoryName, HashMap<RepositoryName, RepositoryName>>
+ externalPackageRepositoryMappings = new HashMap<>();
+ // The map of repository reassignments for BUILD packages loaded within external repositories.
+ // It will be empty for packages within the main workspace.
+ private ImmutableMap<RepositoryName, RepositoryName> repositoryMapping = ImmutableMap.of();
private Path filename = null;
private Label buildFileLabel = null;
private InputFile buildFile = null;
@@ -802,6 +881,50 @@ public class Package {
}
/**
+ * Updates the externalPackageRepositoryMappings entry for {@code repoWithin}. Adds new
+ * entry from {@code localName} to {@code mappedName} in {@code repoWithin}'s map.
+ *
+ * @param repoWithin the RepositoryName within which the mapping should apply
+ * @param localName the RepositoryName that actually appears in the WORKSPACE and BUILD files
+ * in the {@code repoWithin} repository
+ * @param mappedName the RepositoryName by which localName should be referenced
+ */
+ public Builder addRepositoryMappingEntry(
+ RepositoryName repoWithin, RepositoryName localName, RepositoryName mappedName) {
+ HashMap<RepositoryName, RepositoryName> mapping =
+ externalPackageRepositoryMappings
+ .computeIfAbsent(repoWithin, (RepositoryName k) -> new HashMap<>());
+ mapping.put(localName, mappedName);
+ return this;
+ }
+
+ /** Adds all the mappings from a given {@link Package}. */
+ public Builder addRepositoryMappings(Package aPackage) {
+ ImmutableMap<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>>
+ repositoryMappings = aPackage.externalPackageRepositoryMappings;
+ for (Map.Entry<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>> repositoryName :
+ repositoryMappings.entrySet()) {
+ for (Map.Entry<RepositoryName, RepositoryName> repositoryNameRepositoryNameEntry :
+ repositoryName.getValue().entrySet()) {
+ addRepositoryMappingEntry(
+ repositoryName.getKey(),
+ repositoryNameRepositoryNameEntry.getKey(),
+ repositoryNameRepositoryNameEntry.getValue());
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Sets the repository mapping for a regular, BUILD file package (i.e. not the //external
+ * package)
+ */
+ Builder setRepositoryMapping(ImmutableMap<RepositoryName, RepositoryName> repositoryMapping) {
+ this.repositoryMapping = repositoryMapping;
+ return this;
+ }
+
+ /**
* Sets the name of this package's BUILD file.
*/
Builder setFilename(Path filename) {
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
index 71bf904666..d9da36f945 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -26,6 +26,7 @@ import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.LabelValidator;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
@@ -1250,6 +1251,7 @@ public final class PackageFactory {
new AstParseResult(buildFileAST, localReporterForParsing);
return createPackageFromAst(
workspaceName,
+ /*repositoryMapping=*/ ImmutableMap.of(),
packageId,
buildFile,
astParseResult,
@@ -1274,6 +1276,7 @@ public final class PackageFactory {
public Package.Builder createPackageFromAst(
String workspaceName,
+ ImmutableMap<RepositoryName, RepositoryName> repositoryMapping,
PackageIdentifier packageId,
Path buildFile,
AstParseResult astParseResult,
@@ -1297,7 +1300,8 @@ public final class PackageFactory {
defaultVisibility,
skylarkSemantics,
imports,
- skylarkFileDependencies);
+ skylarkFileDependencies,
+ repositoryMapping);
} catch (InterruptedException e) {
globber.onInterrupt();
throw e;
@@ -1599,7 +1603,8 @@ public final class PackageFactory {
RuleVisibility defaultVisibility,
SkylarkSemantics skylarkSemantics,
Map<String, Extension> imports,
- ImmutableList<Label> skylarkFileDependencies)
+ ImmutableList<Label> skylarkFileDependencies,
+ ImmutableMap<RepositoryName, RepositoryName> repositoryMapping)
throws InterruptedException {
Package.Builder pkgBuilder = new Package.Builder(packageBuilderHelper.createFreshPackage(
packageId, ruleClassProvider.getRunfilesPrefix()));
@@ -1622,7 +1627,8 @@ public final class PackageFactory {
// set default_visibility once, be reseting the PackageBuilder.defaultVisibilitySet flag.
.setDefaultVisibilitySet(false)
.setSkylarkFileDependencies(skylarkFileDependencies)
- .setWorkspaceName(workspaceName);
+ .setWorkspaceName(workspaceName)
+ .setRepositoryMapping(repositoryMapping);
Event.replayEventsOn(eventHandler, pastEvents);
for (Postable post : pastPosts) {
diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
index b9d86ad461..132c511c04 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.LabelValidator;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.events.NullEventHandler;
@@ -55,6 +56,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
/**
@@ -278,6 +280,7 @@ public class WorkspaceFactory {
}
builder.addRegisteredExecutionPlatforms(aPackage.getRegisteredExecutionPlatforms());
builder.addRegisteredToolchains(aPackage.getRegisteredToolchains());
+ builder.addRepositoryMappings(aPackage);
for (Rule rule : aPackage.getTargets(Rule.class)) {
try {
// The old rule references another Package instance and we wan't to keep the invariant that
@@ -466,8 +469,8 @@ public class WorkspaceFactory {
};
/**
- * Returns a function-value implementing the build rule "ruleClass" (e.g. cc_library) in the
- * specified package context.
+ * Returns a function-value implementing the build or workspace rule "ruleClass" (e.g. cc_library)
+ * in the specified package context.
*/
private static BuiltinFunction newRuleFunction(
final RuleFactory ruleFactory, final String ruleClassName, final boolean allowOverride) {
@@ -487,11 +490,29 @@ public class WorkspaceFactory {
+ kwargs.get("name")
+ "')");
}
+ if (kwargs.containsKey("repo_mapping")) {
+ if (!(kwargs.get("repo_mapping") instanceof Map)) {
+ throw new EvalException(
+ ast.getLocation(),
+ "Invalid value for 'repo_mapping': '" + kwargs.get("repo_mapping")
+ + "'. Value must be a map."
+ );
+ }
+ @SuppressWarnings("unchecked")
+ Map<String, String> map = (Map<String, String>) kwargs.get("repo_mapping");
+ String externalRepoName = (String) kwargs.get("name");
+ for (Map.Entry<String, String> e : map.entrySet()) {
+ builder.addRepositoryMappingEntry(
+ RepositoryName.createFromValidStrippedName(externalRepoName),
+ RepositoryName.create((String) e.getKey()),
+ RepositoryName.create((String) e.getValue()));
+ }
+ }
RuleClass ruleClass = ruleFactory.getRuleClass(ruleClassName);
RuleClass bindRuleClass = ruleFactory.getRuleClass("bind");
Rule rule =
WorkspaceFactoryHelper.createAndAddRepositoryRule(
- builder, ruleClass, bindRuleClass, kwargs, ast);
+ builder, ruleClass, bindRuleClass, getFinalKwargs(kwargs), ast);
if (!isLegalWorkspaceName(rule.getName())) {
throw new EvalException(
ast.getLocation(), rule + "'s name field must be a legal workspace name");
@@ -506,6 +527,14 @@ public class WorkspaceFactory {
};
}
+ private static Map<String, Object> getFinalKwargs(Map<String, Object> kwargs) {
+ // 'repo_mapping' is not an explicit attribute of any rule and so it would
+ // result in a rule error if propagated to the rule factory.
+ return kwargs.entrySet().stream()
+ .filter(x -> !x.getKey().equals("repo_mapping"))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ }
+
private static ImmutableMap<String, BaseFunction> createWorkspaceFunctions(
boolean allowOverride, RuleFactory ruleFactory) {
Map<String, BaseFunction> map = new HashMap<>();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
index d1de91b1c9..6f7a53f96b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
@@ -29,6 +29,7 @@ import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
@@ -419,6 +420,16 @@ public class PackageFunction implements SkyFunction {
return null;
}
String workspaceName = workspaceNameValue.getName();
+
+ RepositoryMappingValue repositoryMappingValue =
+ (RepositoryMappingValue)
+ env.getValue(RepositoryMappingValue.key(packageId.getRepository()));
+ if (repositoryMappingValue == null) {
+ return null;
+ }
+ ImmutableMap<RepositoryName, RepositoryName> repositoryMapping =
+ repositoryMappingValue.getRepositoryMapping();
+
RootedPath buildFileRootedPath = packageLookupValue.getRootedPath(packageId);
FileValue buildFileValue = null;
Path buildFilePath = buildFileRootedPath.asPath();
@@ -474,6 +485,7 @@ public class PackageFunction implements SkyFunction {
LoadedPackageCacheEntry packageCacheEntry =
loadPackage(
workspaceName,
+ repositoryMapping,
replacementContents,
packageId,
buildFilePath,
@@ -1150,6 +1162,7 @@ public class PackageFunction implements SkyFunction {
@Nullable
private LoadedPackageCacheEntry loadPackage(
String workspaceName,
+ ImmutableMap<RepositoryName, RepositoryName> repositoryMapping,
@Nullable String replacementContents,
PackageIdentifier packageId,
Path buildFilePath,
@@ -1230,16 +1243,18 @@ public class PackageFunction implements SkyFunction {
GlobberWithSkyframeGlobDeps globberWithSkyframeGlobDeps =
makeGlobber(buildFilePath, packageId, packageRoot, env);
long startTimeNanos = BlazeClock.nanoTime();
- Package.Builder pkgBuilder = packageFactory.createPackageFromAst(
- workspaceName,
- packageId,
- buildFilePath,
- astParseResult,
- importResult.importMap,
- importResult.fileDependencies,
- defaultVisibility,
- skylarkSemantics,
- globberWithSkyframeGlobDeps);
+ Package.Builder pkgBuilder =
+ packageFactory.createPackageFromAst(
+ workspaceName,
+ repositoryMapping,
+ packageId,
+ buildFilePath,
+ astParseResult,
+ importResult.importMap,
+ importResult.fileDependencies,
+ defaultVisibility,
+ skylarkSemantics,
+ globberWithSkyframeGlobDeps);
long loadTimeNanos = Math.max(BlazeClock.nanoTime() - startTimeNanos, 0L);
packageCacheEntry = new LoadedPackageCacheEntry(
pkgBuilder,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java
new file mode 100644
index 0000000000..51e697ae84
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java
@@ -0,0 +1,63 @@
+// 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.lib.skyframe;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+import javax.annotation.Nullable;
+
+/** {@link SkyFunction} for {@link RepositoryMappingValue}s. */
+public class RepositoryMappingFunction implements SkyFunction {
+
+ @Nullable
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env)
+ throws SkyFunctionException, InterruptedException {
+ SkyKey externalPackageKey = PackageValue.key(Label.EXTERNAL_PACKAGE_IDENTIFIER);
+ PackageValue externalPackageValue = (PackageValue) env.getValue(externalPackageKey);
+ if (env.valuesMissing()) {
+ return null;
+ }
+ Package externalPackage = externalPackageValue.getPackage();
+ if (externalPackage.containsErrors()) {
+ throw new RepositoryMappingFunctionException();
+ }
+
+ ImmutableMap<RepositoryName, RepositoryName> mapping =
+ externalPackage.getRepositoryMapping((RepositoryName) skyKey.argument());
+ return RepositoryMappingValue.withMapping(mapping);
+ }
+
+ @Nullable
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return null;
+ }
+
+ private class RepositoryMappingFunctionException extends SkyFunctionException {
+ RepositoryMappingFunctionException() {
+ super(
+ new BuildFileContainsErrorsException(Label.EXTERNAL_PACKAGE_IDENTIFIER),
+ Transience.PERSISTENT);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java
new file mode 100644
index 0000000000..809a86d3a9
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java
@@ -0,0 +1,110 @@
+// 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.lib.skyframe;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Interner;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.concurrent.BlazeInterners;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.skyframe.AbstractSkyKey;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+import java.util.Objects;
+
+/**
+ * A value that represents the 'mappings' of an external Bazel workspace, as defined
+ * in the main WORKSPACE file. The SkyValue contains the mappings themselves, with the key being
+ * the name of the external repository.
+ *
+ * <p>Given the following rule:
+ * <pre>{@code
+ * local_repository(
+ * name = “a”,
+ * path = “../a”,
+ * repo_mapping = {“@x” : “@y”}
+ * )
+ * }</pre>
+ *
+ * <p>The SkyKey would be {@code "@a"} and the SkyValue would be the map {@code {"@x" : "@y"}}
+ *
+ * <p>This is kept as a separate value with trivial change pruning so as to not necessitate a
+ * dependency from every {@link PackageValue} to the //external {@link PackageValue}, so that
+ * changes to things in the WORKSPACE other than the mappings (and name) won't require reloading
+ * all packages. If the mappings are changed then the external packages need to be reloaded.
+ */
+public class RepositoryMappingValue implements SkyValue {
+
+ private final ImmutableMap<RepositoryName, RepositoryName> repositoryMapping;
+
+ private RepositoryMappingValue(ImmutableMap<RepositoryName, RepositoryName> repositoryMapping) {
+ this.repositoryMapping = repositoryMapping;
+ }
+
+ /** Returns the workspace mappings. */
+ public ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping() {
+ return repositoryMapping;
+ }
+
+ /** Returns the {@link Key} for {@link RepositoryMappingValue}s. */
+ public static Key key(RepositoryName repositoryName) {
+ return RepositoryMappingValue.Key.create(repositoryName);
+ }
+
+ /** Returns a {@link RepositoryMappingValue} for a workspace with the given name. */
+ public static RepositoryMappingValue withMapping(
+ ImmutableMap<RepositoryName, RepositoryName> repositoryMapping) {
+ return new RepositoryMappingValue(Preconditions.checkNotNull(repositoryMapping));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof RepositoryMappingValue)) {
+ return false;
+ }
+ RepositoryMappingValue other = (RepositoryMappingValue) o;
+ return Objects.equals(repositoryMapping, other.repositoryMapping);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(repositoryMapping);
+ }
+
+ /** {@link SkyKey} for {@link RepositoryMappingValue}. */
+ @AutoCodec.VisibleForSerialization
+ @AutoCodec
+ static class Key extends AbstractSkyKey<RepositoryName> {
+
+ private static final Interner<Key> interner = BlazeInterners.newWeakInterner();
+
+ private Key(RepositoryName arg) {
+ super(arg);
+ }
+
+ @AutoCodec.VisibleForSerialization
+ @AutoCodec.Instantiator
+ static Key create(RepositoryName arg) {
+ return interner.intern(new Key(arg));
+ }
+
+ @Override
+ public SkyFunctionName functionName() {
+ return SkyFunctions.REPOSITORY_MAPPING;
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
index 4d347e8783..7b9ca6d81f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
@@ -114,6 +114,8 @@ public final class SkyFunctions {
SkyFunctionName.create("REGISTERED_TOOLCHAINS");
public static final SkyFunctionName TOOLCHAIN_RESOLUTION =
SkyFunctionName.create("TOOLCHAIN_RESOLUTION");
+ public static final SkyFunctionName REPOSITORY_MAPPING =
+ SkyFunctionName.create("REPOSITORY_MAPPING");
public static Predicate<SkyKey> isSkyFunction(final SkyFunctionName functionName) {
return new Predicate<SkyKey>() {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index c0bb40456d..906924fa9f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -530,6 +530,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
SkyFunctions.REGISTERED_EXECUTION_PLATFORMS, new RegisteredExecutionPlatformsFunction());
map.put(SkyFunctions.REGISTERED_TOOLCHAINS, new RegisteredToolchainsFunction());
map.put(SkyFunctions.TOOLCHAIN_RESOLUTION, new ToolchainResolutionFunction());
+ map.put(SkyFunctions.REPOSITORY_MAPPING, new RepositoryMappingFunction());
map.putAll(extraSkyFunctions);
return map.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
index 7ca43d003b..d8f4cb8b83 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java
@@ -61,6 +61,7 @@ import com.google.devtools.build.lib.skyframe.PackageValue;
import com.google.devtools.build.lib.skyframe.PerBuildSyscallCache;
import com.google.devtools.build.lib.skyframe.PrecomputedFunction;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
+import com.google.devtools.build.lib.skyframe.RepositoryMappingFunction;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.skyframe.SkylarkImportLookupFunction;
import com.google.devtools.build.lib.skyframe.WorkspaceASTFunction;
@@ -415,6 +416,7 @@ public abstract class AbstractPackageLoader implements PackageLoader {
SkyFunctions.WORKSPACE_FILE,
new WorkspaceFileFunction(ruleClassProvider, pkgFactory, directories))
.put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction())
+ .put(SkyFunctions.REPOSITORY_MAPPING, new RepositoryMappingFunction())
.put(
SkyFunctions.PACKAGE,
new PackageFunction(