aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/packages
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/google/devtools/build/lib/packages
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/google/devtools/build/lib/packages')
-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
3 files changed, 164 insertions, 6 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<>();