diff options
author | dannark <dannark@google.com> | 2018-06-21 11:55:44 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-06-21 11:57:27 -0700 |
commit | f24479d495df540bae634b5ff2dde3177585c2a3 (patch) | |
tree | ab16e9bf0c46f1f2b1ad70d6502003de553abd81 /src/main/java/com | |
parent | 9594d5e8dc465bb4526a2f15a4b547de7e1324a7 (diff) |
Take into account repository mapping when processing labels inside BUILD files within external repositories.
For example:
a/BUILD
genrule(
name = "a",
srcs = ["@x//:x.txt"],
outs = ["result.txt"],
cmd = "echo hello > \$(location result.txt)"
)
If the main workspace file references that repository with a rule:
local_repository(
name = "other_repo",
path = "../a",
repo_mapping = {"@x" : "@y"}
)
Then when a/BUILD is evaluated, the string "@x//:x.txt" will be turned into a Label "@y//:x.txt"
RELNOTES: None
PiperOrigin-RevId: 201562148
Diffstat (limited to 'src/main/java/com')
4 files changed, 127 insertions, 37 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java index 6f238429eb..91106b272c 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java @@ -533,12 +533,32 @@ public final class Label } ) public Label getRelative(String relName) throws LabelSyntaxException { + return getRelativeWithRemapping(relName, /* repositoryMapping= */ ImmutableMap.of()); + } + + /** + * Resolves a relative or absolute label name. If given name is absolute, then this method calls + * {@link #parseAbsolute}. Otherwise, it calls {@link #getLocalTargetLabel}. + * + * <p>For example: {@code :quux} relative to {@code //foo/bar:baz} is {@code //foo/bar:quux}; + * {@code //wiz:quux} relative to {@code //foo/bar:baz} is {@code //wiz:quux}; + * {@code @repo//foo:bar} relative to anything will be {@code @repo//foo:bar} if {@code @repo} is + * not in {@code repositoryMapping} but will be {@code @other_repo//foo:bar} if there is an entry + * {@code @repo -> @other_repo} in {@code repositoryMapping} + * + * @param relName the relative label name; must be non-empty + * @param repositoryMapping the map of local repository names in external repository to global + * repository names in main repo; can be empty, but not null + */ + public Label getRelativeWithRemapping( + String relName, ImmutableMap<RepositoryName, RepositoryName> repositoryMapping) + throws LabelSyntaxException { if (relName.length() == 0) { throw new LabelSyntaxException("empty package-relative label"); } if (LabelValidator.isAbsolute(relName)) { - return resolveRepositoryRelative(parseAbsolute(relName, false)); + return resolveRepositoryRelative(parseAbsolute(relName, false, repositoryMapping)); } else if (relName.equals(":")) { throw new LabelSyntaxException("':' is not a valid package-relative label"); } else if (relName.charAt(0) == ':') { diff --git a/src/main/java/com/google/devtools/build/lib/packages/BuildType.java b/src/main/java/com/google/devtools/build/lib/packages/BuildType.java index 96042edbd0..d7811acc32 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/BuildType.java +++ b/src/main/java/com/google/devtools/build/lib/packages/BuildType.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; +import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.packages.License.DistributionType; import com.google.devtools.build.lib.packages.License.LicenseParsingException; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; @@ -145,7 +146,7 @@ public final class BuildType { * <p>The caller is responsible for casting the returned value appropriately. */ public static <T> Object selectableConvert( - Type type, Object x, Object what, @Nullable Label context) + Type<T> type, Object x, Object what, LabelConversionContext context) throws ConversionException { if (x instanceof com.google.devtools.build.lib.syntax.SelectorList) { return new SelectorList<T>( @@ -196,6 +197,31 @@ public final class BuildType { } } + /** Context in which to evaluate a label with repository remappings */ + public static class LabelConversionContext { + private final Label label; + private final ImmutableMap<RepositoryName, RepositoryName> repositoryMapping; + + public LabelConversionContext( + Label label, ImmutableMap<RepositoryName, RepositoryName> repositoryMapping) { + this.label = label; + this.repositoryMapping = repositoryMapping; + } + + public Label getLabel() { + return label; + } + + public ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping() { + return repositoryMapping; + } + + @Override + public String toString() { + return label.toString(); + } + } + private static class LabelType extends Type<Label> { private final LabelClass labelClass; @@ -236,10 +262,24 @@ public final class BuildType { return (Label) x; } try { - if (x instanceof String && context == null) { + if (!(x instanceof String)) { + throw new ConversionException(Type.STRING, x, what); + } + // TODO(b/110101445): check if context is ever actually null + if (context == null) { return Label.parseAbsolute((String) x, false); + // TODO(b/110308446): remove instances of context being a Label + } else if (context instanceof Label) { + return ((Label) context).getRelative(STRING.convert(x, what, context)); + } else if (context instanceof LabelConversionContext) { + LabelConversionContext labelConversionContext = (LabelConversionContext) context; + return labelConversionContext + .getLabel() + .getRelativeWithRemapping( + STRING.convert(x, what, context), labelConversionContext.getRepositoryMapping()); + } else { + throw new ConversionException("invalid context '" + context + "' in " + what); } - return ((Label) context).getRelative(STRING.convert(x, what, context)); } catch (LabelSyntaxException e) { throw new ConversionException("invalid label '" + x + "' in " + what + ": " + e.getMessage()); @@ -259,7 +299,7 @@ public final class BuildType { public static <ValueT> LabelKeyedDictType<ValueT> create(Type<ValueT> valueType) { Preconditions.checkArgument( valueType.getLabelClass() == LabelClass.NONE - || valueType.getLabelClass() == LabelClass.DEPENDENCY, + || valueType.getLabelClass() == LabelClass.DEPENDENCY, "Values associated with label keys must not be labels themselves."); return new LabelKeyedDictType<>(valueType); } @@ -428,16 +468,22 @@ public final class BuildType { } try { // Enforce value is relative to the context. - Label currentRule = (Label) context; - Label result = currentRule.getRelative(value); + Label currentRule; + ImmutableMap<RepositoryName, RepositoryName> repositoryMapping = ImmutableMap.of(); + if (context instanceof LabelConversionContext) { + currentRule = ((LabelConversionContext) context).getLabel(); + repositoryMapping = ((LabelConversionContext) context).getRepositoryMapping(); + } else { + throw new ConversionException("invalid context '" + context + "' in " + what); + } + Label result = currentRule.getRelativeWithRemapping(value, repositoryMapping); if (!result.getPackageIdentifier().equals(currentRule.getPackageIdentifier())) { throw new ConversionException("label '" + value + "' is not in the current package"); } return result; } catch (LabelSyntaxException e) { throw new ConversionException( - "illegal output file name '" + value + "' in rule " + context + ": " - + e.getMessage()); + "illegal output file name '" + value + "' in rule " + context + ": " + e.getMessage()); } } } @@ -452,8 +498,9 @@ public final class BuildType { private final List<Selector<T>> elements; @VisibleForTesting - SelectorList(List<Object> x, Object what, @Nullable Label context, - Type<T> originalType) throws ConversionException { + SelectorList( + List<Object> x, Object what, @Nullable LabelConversionContext context, Type<T> originalType) + throws ConversionException { if (x.size() > 1 && originalType.concat(ImmutableList.<T>of()) == null) { throw new ConversionException( String.format("type '%s' doesn't support select concatenation", originalType)); @@ -500,11 +547,11 @@ public final class BuildType { public Set<Label> getKeyLabels() { ImmutableSet.Builder<Label> keys = ImmutableSet.builder(); for (Selector<T> selector : getSelectors()) { - for (Label label : selector.getEntries().keySet()) { - if (!Selector.isReservedLabel(label)) { - keys.add(label); - } - } + for (Label label : selector.getEntries().keySet()) { + if (!Selector.isReservedLabel(label)) { + keys.add(label); + } + } } return keys.build(); } @@ -550,19 +597,24 @@ public final class BuildType { private final String noMatchError; private final boolean hasDefaultCondition; - /** - * Creates a new Selector using the default error message when no conditions match. - */ - Selector(ImmutableMap<?, ?> x, Object what, @Nullable Label context, Type<T> originalType) + /** Creates a new Selector using the default error message when no conditions match. */ + Selector( + ImmutableMap<?, ?> x, + Object what, + @Nullable LabelConversionContext context, + Type<T> originalType) throws ConversionException { this(x, what, context, originalType, ""); } - /** - * Creates a new Selector with a custom error message for when no conditions match. - */ - Selector(ImmutableMap<?, ?> x, Object what, @Nullable Label context, Type<T> originalType, - String noMatchError) throws ConversionException { + /** Creates a new Selector with a custom error message for when no conditions match. */ + Selector( + ImmutableMap<?, ?> x, + Object what, + @Nullable LabelConversionContext context, + Type<T> originalType, + String noMatchError) + throws ConversionException { this.originalType = originalType; LinkedHashMap<Label, T> result = Maps.newLinkedHashMapWithExpectedSize(x.size()); ImmutableSet.Builder<Label> defaultValuesBuilder = ImmutableSet.builder(); 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 d6f7944288..3d84851a22 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 @@ -926,6 +926,11 @@ public class Package { return this; } + /** Get the repository mapping for this package */ + ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping() { + return this.repositoryMapping; + } + /** * Sets the name of this package's BUILD file. */ diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java index fba4c92a65..15349b10a3 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java @@ -36,11 +36,13 @@ import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition 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.events.EventHandler; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.events.NullEventHandler; import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate; import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate.CannotPrecomputeDefaultsException; +import com.google.devtools.build.lib.packages.BuildType.LabelConversionContext; import com.google.devtools.build.lib.packages.BuildType.SelectorList; import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy.MissingFragmentPolicy; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; @@ -1766,7 +1768,8 @@ public class RuleClass { EventHandler eventHandler) throws InterruptedException, CannotPrecomputeDefaultsException { BitSet definedAttrIndices = - populateDefinedRuleAttributeValues(rule, attributeValues, eventHandler); + populateDefinedRuleAttributeValues( + rule, pkgBuilder.getRepositoryMapping(), attributeValues, eventHandler); populateDefaultRuleAttributeValues(rule, pkgBuilder, definedAttrIndices, eventHandler); // Now that all attributes are bound to values, collect and store configurable attribute keys. populateConfigDependenciesAttribute(rule); @@ -1779,12 +1782,15 @@ public class RuleClass { * <p>Handles the special cases of the attribute named {@code "name"} and attributes with value * {@link Runtime#NONE}. * - * <p>Returns a bitset {@code b} where {@code b.get(i)} is {@code true} if this method set a - * value for the attribute with index {@code i} in this {@link RuleClass}. Errors are reported - * on {@code eventHandler}. + * <p>Returns a bitset {@code b} where {@code b.get(i)} is {@code true} if this method set a value + * for the attribute with index {@code i} in this {@link RuleClass}. Errors are reported on {@code + * eventHandler}. */ private <T> BitSet populateDefinedRuleAttributeValues( - Rule rule, AttributeValues<T> attributeValues, EventHandler eventHandler) { + Rule rule, + ImmutableMap<RepositoryName, RepositoryName> repositoryMapping, + AttributeValues<T> attributeValues, + EventHandler eventHandler) { BitSet definedAttrIndices = new BitSet(); for (T attributeAccessor : attributeValues.getAttributeAccessors()) { String attributeName = attributeValues.getName(attributeAccessor); @@ -1809,7 +1815,8 @@ public class RuleClass { Object nativeAttributeValue; if (attributeValues.valuesAreBuildLanguageTyped()) { try { - nativeAttributeValue = convertFromBuildLangType(rule, attr, attributeValue); + nativeAttributeValue = + convertFromBuildLangType(rule, attr, attributeValue, repositoryMapping); } catch (ConversionException e) { rule.reportError(String.format("%s: %s", rule.getLabel(), e.getMessage()), eventHandler); continue; @@ -2105,13 +2112,19 @@ public class RuleClass { * <p>Throws {@link ConversionException} if the conversion fails, or if {@code buildLangValue} is * a selector expression but {@code attr.isConfigurable()} is {@code false}. */ - private static Object convertFromBuildLangType(Rule rule, Attribute attr, Object buildLangValue) + private static Object convertFromBuildLangType( + Rule rule, + Attribute attr, + Object buildLangValue, + ImmutableMap<RepositoryName, RepositoryName> repositoryMapping) throws ConversionException { - Object converted = BuildType.selectableConvert( - attr.getType(), - buildLangValue, - new AttributeConversionContext(attr.getName(), rule.getRuleClass()), - rule.getLabel()); + LabelConversionContext context = new LabelConversionContext(rule.getLabel(), repositoryMapping); + Object converted = + BuildType.selectableConvert( + attr.getType(), + buildLangValue, + new AttributeConversionContext(attr.getName(), rule.getRuleClass()), + context); if ((converted instanceof SelectorList<?>) && !attr.isConfigurable()) { throw new ConversionException( |