diff options
Diffstat (limited to 'src')
25 files changed, 650 insertions, 211 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java index 2cced64191..5afda9f349 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java @@ -794,13 +794,13 @@ public class BuildView { * Returns ConfigMatchingProvider instances corresponding to the configurable attribute keys * present in this rule's attributes. */ - private Set<ConfigMatchingProvider> getConfigurableAttributeKeysForTesting( + private ImmutableMap<Label, ConfigMatchingProvider> getConfigurableAttributeKeysForTesting( EventHandler eventHandler, TargetAndConfiguration ctg) { if (!(ctg.getTarget() instanceof Rule)) { - return ImmutableSet.of(); + return ImmutableMap.of(); } Rule rule = (Rule) ctg.getTarget(); - ImmutableSet.Builder<ConfigMatchingProvider> keys = ImmutableSet.builder(); + ImmutableMap.Builder<Label, ConfigMatchingProvider> keys = ImmutableMap.builder(); RawAttributeMapper mapper = RawAttributeMapper.of(rule); for (Attribute attribute : rule.getAttributes()) { for (Label label : mapper.getConfigurabilityKeys(attribute.getName(), attribute.getType())) { @@ -809,7 +809,7 @@ public class BuildView { } ConfiguredTarget ct = getConfiguredTargetForTesting( eventHandler, label, ctg.getConfiguration()); - keys.add(Preconditions.checkNotNull(ct.getProvider(ConfigMatchingProvider.class))); + keys.put(label, Preconditions.checkNotNull(ct.getProvider(ConfigMatchingProvider.class))); } } return keys.build(); @@ -876,7 +876,7 @@ public class BuildView { .setVisibility(NestedSetBuilder.<PackageSpecification>create( Order.STABLE_ORDER, PackageSpecification.EVERYTHING)) .setPrerequisites(getPrerequisiteMapForTesting(eventHandler, target, configurations)) - .setConfigConditions(ImmutableSet.<ConfigMatchingProvider>of()) + .setConfigConditions(ImmutableMap.<Label, ConfigMatchingProvider>of()) .setUniversalFragment(ruleClassProvider.getUniversalFragment()) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java index 16f8f602d6..ecf25bd9ad 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java @@ -25,6 +25,7 @@ import com.google.devtools.build.lib.actions.BaseSpawn; import com.google.devtools.build.lib.analysis.actions.FileWriteAction; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.rules.AliasProvider; import com.google.devtools.build.lib.syntax.SkylarkDict; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkList.MutableList; @@ -115,7 +116,7 @@ public final class CommandHelper { } for (TransitiveInfoCollection dep : tools) { // (Note: host configuration) - Label label = dep.getLabel(); + Label label = AliasProvider.getDependencyLabel(dep); FilesToRunProvider tool = dep.getProvider(FilesToRunProvider.class); if (tool == null) { continue; diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAttributeMapper.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAttributeMapper.java index 87e1fad7d5..2974c3a097 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAttributeMapper.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAttributeMapper.java @@ -59,14 +59,11 @@ public class ConfiguredAttributeMapper extends AbstractAttributeMapper { private final Map<Label, ConfigMatchingProvider> configConditions; private Rule rule; - private ConfiguredAttributeMapper(Rule rule, Set<ConfigMatchingProvider> configConditions) { + private ConfiguredAttributeMapper(Rule rule, + ImmutableMap<Label, ConfigMatchingProvider> configConditions) { super(Preconditions.checkNotNull(rule).getPackage(), rule.getRuleClassObject(), rule.getLabel(), rule.getAttributeContainer()); - ImmutableMap.Builder<Label, ConfigMatchingProvider> builder = ImmutableMap.builder(); - for (ConfigMatchingProvider configCondition : configConditions) { - builder.put(configCondition.label(), configCondition); - } - this.configConditions = builder.build(); + this.configConditions = configConditions; this.rule = rule; } @@ -86,7 +83,7 @@ public class ConfiguredAttributeMapper extends AbstractAttributeMapper { */ @VisibleForTesting public static ConfiguredAttributeMapper of( - Rule rule, Set<ConfigMatchingProvider> configConditions) { + Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions) { return new ConfiguredAttributeMapper(rule, configConditions); } @@ -154,8 +151,12 @@ public class ConfiguredAttributeMapper extends AbstractAttributeMapper { continue; } - ConfigMatchingProvider curCondition = Verify.verifyNotNull(configConditions.get( - rule.getLabel().resolveRepositoryRelative(selectorKey))); + ConfigMatchingProvider curCondition = configConditions.get( + rule.getLabel().resolveRepositoryRelative(selectorKey)); + if (curCondition == null) { + // This can happen if the rule is in error + continue; + } conditionLabels.add(curCondition.label()); if (curCondition.matches()) { diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java index 39a0e674ff..5e393412bb 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.analysis; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ListMultimap; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ArtifactFactory; @@ -164,7 +165,7 @@ public final class ConfiguredTargetFactory { public final ConfiguredTarget createConfiguredTarget(AnalysisEnvironment analysisEnvironment, ArtifactFactory artifactFactory, Target target, BuildConfiguration config, BuildConfiguration hostConfig, ListMultimap<Attribute, ConfiguredTarget> prerequisiteMap, - Set<ConfigMatchingProvider> configConditions) + ImmutableMap<Label, ConfigMatchingProvider> configConditions) throws InterruptedException { if (target instanceof Rule) { return createRule(analysisEnvironment, (Rule) target, config, hostConfig, @@ -219,7 +220,7 @@ public final class ConfiguredTargetFactory { AnalysisEnvironment env, Rule rule, BuildConfiguration configuration, BuildConfiguration hostConfiguration, ListMultimap<Attribute, ConfiguredTarget> prerequisiteMap, - Set<ConfigMatchingProvider> configConditions) throws InterruptedException { + ImmutableMap<Label, ConfigMatchingProvider> configConditions) throws InterruptedException { // Visibility computation and checking is done for every rule. RuleContext ruleContext = new RuleContext.Builder( @@ -303,7 +304,7 @@ public final class ConfiguredTargetFactory { ConfiguredAspectFactory aspectFactory, Aspect aspect, ListMultimap<Attribute, ConfiguredTarget> prerequisiteMap, - Set<ConfigMatchingProvider> configConditions, + ImmutableMap<Label, ConfigMatchingProvider> configConditions, BuildConfiguration aspectConfiguration, BuildConfiguration hostConfiguration) throws InterruptedException { diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java index 107a0fc61b..f71f853de8 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.analysis; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; @@ -84,7 +85,7 @@ public abstract class DependencyResolver { TargetAndConfiguration node, BuildConfiguration hostConfig, Aspect aspect, - Set<ConfigMatchingProvider> configConditions) + ImmutableMap<Label, ConfigMatchingProvider> configConditions) throws EvalException, InterruptedException { NestedSetBuilder<Label> rootCauses = NestedSetBuilder.<Label>stableOrder(); ListMultimap<Attribute, Dependency> outgoingEdges = @@ -118,7 +119,7 @@ public abstract class DependencyResolver { TargetAndConfiguration node, BuildConfiguration hostConfig, Aspect aspect, - Set<ConfigMatchingProvider> configConditions, + ImmutableMap<Label, ConfigMatchingProvider> configConditions, NestedSetBuilder<Label> rootCauses) throws EvalException, InterruptedException { Target target = node.getTarget(); @@ -155,7 +156,8 @@ public abstract class DependencyResolver { private ListMultimap<Attribute, LabelAndConfiguration> resolveAttributes( Rule rule, AspectDefinition aspect, BuildConfiguration configuration, - BuildConfiguration hostConfiguration, Set<ConfigMatchingProvider> configConditions) + BuildConfiguration hostConfiguration, + ImmutableMap<Label, ConfigMatchingProvider> configConditions) throws EvalException, InterruptedException { ConfiguredAttributeMapper attributeMap = ConfiguredAttributeMapper.of(rule, configConditions); attributeMap.validateAttributes(); diff --git a/src/main/java/com/google/devtools/build/lib/analysis/LicensesProviderImpl.java b/src/main/java/com/google/devtools/build/lib/analysis/LicensesProviderImpl.java index 99c2124639..0952d69274 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/LicensesProviderImpl.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/LicensesProviderImpl.java @@ -14,10 +14,13 @@ package com.google.devtools.build.lib.analysis; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.License; +import com.google.devtools.build.lib.packages.Rule; /** * A {@link ConfiguredTarget} that has licensed targets in its transitive closure. @@ -33,6 +36,38 @@ public final class LicensesProviderImpl implements LicensesProvider { this.transitiveLicenses = transitiveLicenses; } + /** + * Create the appropriate {@link LicensesProvider} for a rule based on its {@code RuleContext} + */ + public static LicensesProvider of(RuleContext ruleContext) { + if (!ruleContext.getConfiguration().checkLicenses()) { + return EMPTY; + } + + NestedSetBuilder<TargetLicense> builder = NestedSetBuilder.linkOrder(); + BuildConfiguration configuration = ruleContext.getConfiguration(); + Rule rule = ruleContext.getRule(); + License toolOutputLicense = rule.getToolOutputLicense(ruleContext.attributes()); + if (configuration.isHostConfiguration() && toolOutputLicense != null) { + if (toolOutputLicense != License.NO_LICENSE) { + builder.add(new TargetLicense(rule.getLabel(), toolOutputLicense)); + } + } else { + if (rule.getLicense() != License.NO_LICENSE) { + builder.add(new TargetLicense(rule.getLabel(), rule.getLicense())); + } + + for (TransitiveInfoCollection dep : ruleContext.getConfiguredTargetMap().values()) { + LicensesProvider provider = dep.getProvider(LicensesProvider.class); + if (provider != null) { + builder.addTransitive(provider.getTransitiveLicenses()); + } + } + } + + return new LicensesProviderImpl(builder.build()); + } + @Override public NestedSet<TargetLicense> getTransitiveLicenses() { return transitiveLicenses; diff --git a/src/main/java/com/google/devtools/build/lib/analysis/LocationExpander.java b/src/main/java/com/google/devtools/build/lib/analysis/LocationExpander.java index 9761d6a2b9..be14f5ddb8 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/LocationExpander.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/LocationExpander.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.OutputFile; +import com.google.devtools.build.lib.rules.AliasProvider; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; @@ -283,7 +284,7 @@ public class LocationExpander { if (ruleContext.getRule().isAttrDefined("srcs", BuildType.LABEL_LIST)) { for (TransitiveInfoCollection src : ruleContext .getPrerequisitesIf("srcs", Mode.TARGET, FileProvider.class)) { - Iterables.addAll(mapGet(locationMap, src.getLabel()), + Iterables.addAll(mapGet(locationMap, AliasProvider.getDependencyLabel(src)), src.getProvider(FileProvider.class).getFilesToBuild()); } } @@ -305,7 +306,7 @@ public class LocationExpander { } for (TransitiveInfoCollection dep : depsDataAndTools) { - Label label = dep.getLabel(); + Label label = AliasProvider.getDependencyLabel(dep); FilesToRunProvider filesToRun = dep.getProvider(FilesToRunProvider.class); Artifact executableArtifact = filesToRun.getExecutable(); diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RedirectChaser.java b/src/main/java/com/google/devtools/build/lib/analysis/RedirectChaser.java index a51d2030a1..c0bcfbad5e 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RedirectChaser.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RedirectChaser.java @@ -86,9 +86,8 @@ public final class RedirectChaser { } Label newLabel = getFilegroupRedirect(possibleRedirect); if (newLabel == null) { - newLabel = getBindRedirect(possibleRedirect); + newLabel = getBindOrAliasRedirect(possibleRedirect); } - if (newLabel == null) { return label; } @@ -128,13 +127,14 @@ public final class RedirectChaser { return labels.get(0); } - private static Label getBindRedirect(Target target) throws InvalidConfigurationException { + private static Label getBindOrAliasRedirect(Target target) + throws InvalidConfigurationException { if (!(target instanceof Rule)) { return null; } Rule rule = (Rule) target; - if (!rule.getRuleClass().equals("bind")) { + if (!rule.getRuleClass().equals("bind") && !rule.getRuleClass().equals("alias")) { return null; } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java index 211097f45d..f1980ec6a6 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTarget.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider; import com.google.devtools.build.lib.analysis.config.RunUnder; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.packages.OutputFile; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.rules.SkylarkApiProvider; @@ -25,7 +26,6 @@ import com.google.devtools.build.lib.util.Preconditions; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; /** * A generic implementation of RuleConfiguredTarget. Do not use directly. Use {@link @@ -45,7 +45,7 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { } private final ImmutableMap<Class<? extends TransitiveInfoProvider>, Object> providers; - private final Set<ConfigMatchingProvider> configConditions; + private final ImmutableMap<Label, ConfigMatchingProvider> configConditions; RuleConfiguredTarget(RuleContext ruleContext, ImmutableMap<String, Object> skylarkProviders, @@ -93,7 +93,7 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { /** * The configuration conditions that trigger this rule's configurable attributes. */ - Set<ConfigMatchingProvider> getConfigConditions() { + ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() { return configConditions; } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java index ab7bdafd8e..b6fd29c230 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java @@ -20,8 +20,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.LicensesProvider.TargetLicense; -import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics; import com.google.devtools.build.lib.analysis.constraints.EnvironmentCollection; import com.google.devtools.build.lib.analysis.constraints.SupportedEnvironments; @@ -30,8 +28,6 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.events.Location; -import com.google.devtools.build.lib.packages.License; -import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.rules.test.ExecutionInfoProvider; import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider; @@ -67,7 +63,7 @@ public final class RuleConfiguredTargetBuilder { public RuleConfiguredTargetBuilder(RuleContext ruleContext) { this.ruleContext = ruleContext; - add(LicensesProvider.class, initializeLicensesProvider()); + add(LicensesProvider.class, LicensesProviderImpl.of(ruleContext)); add(VisibilityProvider.class, new VisibilityProviderImpl(ruleContext.getVisibility())); } @@ -215,35 +211,6 @@ public final class RuleConfiguredTargetBuilder { return new TestProvider(testParams, testTags); } - private LicensesProvider initializeLicensesProvider() { - if (!ruleContext.getConfiguration().checkLicenses()) { - return LicensesProviderImpl.EMPTY; - } - - NestedSetBuilder<TargetLicense> builder = NestedSetBuilder.linkOrder(); - BuildConfiguration configuration = ruleContext.getConfiguration(); - Rule rule = ruleContext.getRule(); - License toolOutputLicense = rule.getToolOutputLicense(ruleContext.attributes()); - if (configuration.isHostConfiguration() && toolOutputLicense != null) { - if (toolOutputLicense != License.NO_LICENSE) { - builder.add(new TargetLicense(rule.getLabel(), toolOutputLicense)); - } - } else { - if (rule.getLicense() != License.NO_LICENSE) { - builder.add(new TargetLicense(rule.getLabel(), rule.getLicense())); - } - - for (TransitiveInfoCollection dep : ruleContext.getConfiguredTargetMap().values()) { - LicensesProvider provider = dep.getProvider(LicensesProvider.class); - if (provider != null) { - builder.addTransitive(provider.getTransitiveLicenses()); - } - } - } - - return new LicensesProviderImpl(builder.build()); - } - private <T extends TransitiveInfoProvider> T findProvider(Class<T> clazz) { return clazz.cast(providers.get(clazz)); } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java index 1bf1926197..b22cc12dbf 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java @@ -68,6 +68,7 @@ import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleErrorConsumer; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.packages.TargetUtils; +import com.google.devtools.build.lib.rules.AliasProvider; import com.google.devtools.build.lib.rules.fileset.FilesetProvider; import com.google.devtools.build.lib.shell.ShellUtils; import com.google.devtools.build.lib.syntax.EvalException; @@ -143,7 +144,7 @@ public final class RuleContext extends TargetContext private final Rule rule; private final ListMultimap<String, ConfiguredTarget> targetMap; private final ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap; - private final Set<ConfigMatchingProvider> configConditions; + private final ImmutableMap<Label, ConfigMatchingProvider> configConditions; private final AttributeMap attributes; private final ImmutableSet<String> features; private final String ruleClassNameForLogging; @@ -165,7 +166,7 @@ public final class RuleContext extends TargetContext AttributeMap attributes, ListMultimap<String, ConfiguredTarget> targetMap, ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap, - Set<ConfigMatchingProvider> configConditions, + ImmutableMap<Label, ConfigMatchingProvider> configConditions, Class<? extends BuildConfiguration.Fragment> universalFragment, String ruleClassNameForLogging, ImmutableMap<String, Attribute> aspectAttributes) { @@ -247,7 +248,7 @@ public final class RuleContext extends TargetContext /** * The configuration conditions that trigger this rule's configurable attributes. */ - Set<ConfigMatchingProvider> getConfigConditions() { + ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() { return configConditions; } @@ -1317,7 +1318,7 @@ public final class RuleContext extends TargetContext @Nullable private final String aspectName; private final ErrorReporter reporter; private ListMultimap<Attribute, ConfiguredTarget> prerequisiteMap; - private Set<ConfigMatchingProvider> configConditions; + private ImmutableMap<Label, ConfigMatchingProvider> configConditions; private NestedSet<PackageSpecification> visibility; private ImmutableMap<String, Attribute> aspectAttributes; private ImmutableBiMap<String, Class<? extends TransitiveInfoProvider>> skylarkProviderRegistry; @@ -1390,7 +1391,7 @@ public final class RuleContext extends TargetContext * Sets the configuration conditions needed to determine which paths to follow for this * rule's configurable attributes. */ - Builder setConfigConditions(Set<ConfigMatchingProvider> configConditions) { + Builder setConfigConditions(ImmutableMap<Label, ConfigMatchingProvider> configConditions) { this.configConditions = Preconditions.checkNotNull(configConditions); return this; } @@ -1447,7 +1448,7 @@ public final class RuleContext extends TargetContext * on a PrerequisiteMap instance. */ private ListMultimap<String, ConfiguredFilesetEntry> createFilesetEntryMap( - final Rule rule, Set<ConfigMatchingProvider> configConditions) { + final Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions) { final ImmutableSortedKeyListMultimap.Builder<String, ConfiguredFilesetEntry> mapBuilder = ImmutableSortedKeyListMultimap.builder(); for (Attribute attr : rule.getAttributes()) { @@ -1544,16 +1545,18 @@ public final class RuleContext extends TargetContext } private void reportBadPrerequisite(Attribute attribute, String targetKind, - Label prerequisiteLabel, String reason, boolean isWarning) { + ConfiguredTarget prerequisite, String reason, boolean isWarning) { String msgPrefix = targetKind != null ? targetKind + " " : ""; String msgReason = reason != null ? " (" + reason + ")" : ""; if (isWarning) { attributeWarning(attribute.getName(), String.format( - "%s'%s' is unexpected here%s; continuing anyway", - msgPrefix, prerequisiteLabel, msgReason)); + "%s'%s'%s is unexpected here%s; continuing anyway", + msgPrefix, prerequisite.getLabel(), AliasProvider.printVisibilityChain(prerequisite), + msgReason)); } else { attributeError(attribute.getName(), String.format( - "%s'%s' is misplaced here%s", msgPrefix, prerequisiteLabel, msgReason)); + "%s'%s'%s is misplaced here%s", msgPrefix, prerequisite.getLabel(), + AliasProvider.printVisibilityChain(prerequisite), msgReason)); } } @@ -1568,7 +1571,7 @@ public final class RuleContext extends TargetContext String reason = attribute.getValidityPredicate().checkValid(rule, prerequisiteRule); if (reason != null) { reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), - prerequisiteLabel, reason, false); + prerequisite, reason, false); } } @@ -1593,7 +1596,7 @@ public final class RuleContext extends TargetContext } } else { // The file exists but has a bad extension - reportBadPrerequisite(attribute, "file", prerequisiteLabel, + reportBadPrerequisite(attribute, "file", prerequisite, "expected " + attribute.getAllowedFileTypesPredicate(), false); } } @@ -1752,7 +1755,7 @@ public final class RuleContext extends TargetContext != Predicates.<RuleClass>alwaysTrue()) { allowedWithWarning = attribute.getAllowedRuleClassesWarningPredicate().apply(ruleClass); if (allowedWithWarning) { - reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisiteLabel, + reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisite, "expected " + attribute.getAllowedRuleClassesPredicate(), true); return; } @@ -1777,7 +1780,7 @@ public final class RuleContext extends TargetContext + missingMandatoryProviders); } } else if (Boolean.FALSE.equals(allowed)) { - reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisiteLabel, + reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisite, "expected " + attribute.getAllowedRuleClassesPredicate(), false); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index f2f909a4a0..72cfe3c97e 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -76,6 +76,8 @@ import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.PackageGroup; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.rules.Alias.AliasRule; +import com.google.devtools.build.lib.rules.AliasProvider; import com.google.devtools.build.lib.rules.android.AndroidBinaryOnlyRule; import com.google.devtools.build.lib.rules.android.AndroidConfiguration; import com.google.devtools.build.lib.rules.android.AndroidLibraryBaseRule; @@ -198,10 +200,12 @@ public class BazelRuleClassProvider { } else { // Oddly enough, we use reportError rather than ruleError here. context.reportError(rule.getLocation(), - String.format("Target '%s' is not visible from target '%s'. Check " + String.format("Target '%s' is not visible from target '%s'%s. Check " + "the visibility declaration of the former target if you think " + "the dependency is legitimate", - prerequisiteLabel, rule.getLabel())); + prerequisiteLabel, + rule.getLabel(), + AliasProvider.printVisibilityChain(prerequisite))); } } @@ -305,6 +309,7 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new ConfigRuleClasses.ConfigBaseRule()); builder.addRuleDefinition(new ConfigRuleClasses.ConfigSettingRule()); + builder.addRuleDefinition(new AliasRule()); builder.addRuleDefinition(new BazelFilegroupRule()); builder.addRuleDefinition(new BazelTestSuiteRule()); builder.addRuleDefinition(new BazelGenRuleRule()); diff --git a/src/main/java/com/google/devtools/build/lib/rules/Alias.java b/src/main/java/com/google/devtools/build/lib/rules/Alias.java new file mode 100644 index 0000000000..540bcc953b --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/Alias.java @@ -0,0 +1,120 @@ +// Copyright 2016 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.rules; + +import static com.google.devtools.build.lib.packages.Attribute.ANY_RULE; +import static com.google.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.BuildType.LABEL; + +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.analysis.BaseRuleClasses; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.LicensesProvider; +import com.google.devtools.build.lib.analysis.LicensesProviderImpl; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.analysis.VisibilityProvider; +import com.google.devtools.build.lib.analysis.VisibilityProviderImpl; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; +import com.google.devtools.build.lib.util.FileTypeSet; + +/** + * Implementation of the <code>alias</code> rule. + */ +public class Alias implements RuleConfiguredTargetFactory { + @Override + public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { + ConfiguredTarget actual = (ConfiguredTarget) ruleContext.getPrerequisite("actual", Mode.TARGET); + return new AliasConfiguredTarget( + actual, + ImmutableMap.of( + AliasProvider.class, AliasProvider.fromAliasRule(ruleContext.getLabel(), actual), + VisibilityProvider.class, new VisibilityProviderImpl(ruleContext.getVisibility()), + LicensesProvider.class, LicensesProviderImpl.of(ruleContext))); + } + + /** + * Rule definition. + */ + public static class AliasRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + /*<!-- #BLAZE_RULE(alias).ATTRIBUTE(actual) --> + The target this alias refers to. It does not need to be a rule, it can also be an input + file. + <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/ + .add(attr("actual", LABEL) + .allowedFileTypes(FileTypeSet.ANY_FILE) + .allowedRuleClasses(ANY_RULE) + .mandatory()) + .build(); + } + + @Override + public Metadata getMetadata() { + return Metadata.builder() + .name("alias") + .factoryClass(Alias.class) + .ancestors(BaseRuleClasses.BaseRule.class) + .build(); + } + } +} + +/*<!-- #BLAZE_RULE (NAME = alias, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] --> + +<p> + The <code>alias</code> rule creates another name a rule can be referred to as. +</p> + +<p> + Aliasing only works for "regular" targets. In particular, <code>package_group</code>, + <code>config_setting</code> and <code>test_suite</code> rules cannot be aliased. +</p> + +<p> + The alias rule has its own visibility and license declaration. In all other respects, it behaves + like the rule it references with some minor exceptions: + + <ul> + <li> + Tests are not run if their alias is mentioned on the command line + </li> + <li> + When defining environment groups, the aliases to <code>environment</code> rules are not + supported. They are not supported in the <code>--target_environment</code> command line + option, either. + </li> + </ul> +</p> + +<h4 id="alias_example">Examples</h4> + +<pre class="code"> +filegroup( + name = "data", + srcs = ["data.txt"], +) + +alias( + name = 'other', + actual = ':data', +) +</pre> + +<!-- #END_BLAZE_RULE -->*/ diff --git a/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java new file mode 100644 index 0000000000..c7d2387277 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java @@ -0,0 +1,111 @@ +// Copyright 2016 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.rules; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.SkylarkProviders; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.collect.nestedset.Order; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.syntax.ClassObject; +import com.google.devtools.build.lib.syntax.SkylarkNestedSet; + +/** + * This configured target pretends to be whatever type of target "actual" is, returning its + * transitive info providers and target, but returning its own label. + * + * <p>Transitive info providers can also be overridden. + */ +@Immutable +public final class AliasConfiguredTarget implements ConfiguredTarget, ClassObject { + private final ConfiguredTarget configuredTarget; + private final ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> + overrides; + + public AliasConfiguredTarget(ConfiguredTarget actual, + ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> overrides) { + configuredTarget = actual; + this.overrides = overrides; + } + + @Override + public <P extends TransitiveInfoProvider> P getProvider(Class<P> provider) { + if (overrides.containsKey(provider)) { + return provider.cast(overrides.get(provider)); + } + + return configuredTarget == null ? null : configuredTarget.getProvider(provider); + } + + @Override + public Label getLabel() { + return configuredTarget.getLabel(); + } + + @Override + public Object get(String providerKey) { + return configuredTarget == null ? null : configuredTarget.get(providerKey); + } + + @Override + public Target getTarget() { + return configuredTarget == null ? null : configuredTarget.getTarget(); + } + + @Override + public BuildConfiguration getConfiguration() { + return configuredTarget.getConfiguration(); + } + + /* ClassObject methods */ + + @Override + public Object getValue(String name) { + if (name.equals("label")) { + return getLabel(); + } else if (name.equals("files")) { + // A shortcut for files to build in Skylark. FileConfiguredTarget and RunleConfiguredTarget + // always has FileProvider and Error- and PackageGroupConfiguredTarget-s shouldn't be + // accessible in Skylark. + return SkylarkNestedSet.of(Artifact.class, configuredTarget == null + ? NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER) + : getProvider(FileProvider.class).getFilesToBuild()); + } + return configuredTarget == null ? null : configuredTarget.get(name); + } + + @Override + public ImmutableCollection<String> getKeys() { + ImmutableList.Builder<String> result = ImmutableList.<String>builder().add("label", "files"); + if (configuredTarget != null) { + result.addAll(configuredTarget.getProvider(SkylarkProviders.class).getKeys()); + } + return result.build(); + } + + @Override + public String errorMessage(String name) { + // Use the default error message. + return null; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/AliasProvider.java b/src/main/java/com/google/devtools/build/lib/rules/AliasProvider.java new file mode 100644 index 0000000000..a6950b242a --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/AliasProvider.java @@ -0,0 +1,79 @@ +// Copyright 2016 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.rules; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.util.Preconditions; + +/** + * A provider that gives information about the aliases a rule was resolved through. + */ +@Immutable +public final class AliasProvider implements TransitiveInfoProvider { + // We don't expect long alias chains, so it's better to have a list instead of a nested set + private final ImmutableList<Label> aliasChain; + + public AliasProvider(ImmutableList<Label> aliasChain) { + Preconditions.checkState(!aliasChain.isEmpty()); + this.aliasChain = aliasChain; + } + + public static AliasProvider fromAliasRule(Label label, ConfiguredTarget actual) { + ImmutableList.Builder<Label> chain = ImmutableList.builder(); + chain.add(label); + AliasProvider dep = actual.getProvider(AliasProvider.class); + if (dep != null) { + chain.addAll(dep.getAliasChain()); + } + + return new AliasProvider(chain.build()); + } + + /** + * Returns the label by which it was referred to in the BUILD file. + * + * <p>For non-alias rules, it's the label of the rule itself, for alias rules, it's the label of + * the alias rule. + */ + public static Label getDependencyLabel(TransitiveInfoCollection dep) { + AliasProvider aliasProvider = dep.getProvider(AliasProvider.class); + return aliasProvider != null + ? aliasProvider.getAliasChain().get(0) + : dep.getLabel(); + } + + /** + * Returns the list of aliases from top to bottom (i.e. the last alias depends on the actual + * resolved target and the first alias is the one that was in the attribute of the rule currently + * being analyzed) + */ + public ImmutableList<Label> getAliasChain() { + return aliasChain; + } + + public static String printVisibilityChain(ConfiguredTarget target) { + AliasProvider aliasProvider = target.getProvider(AliasProvider.class); + if (aliasProvider == null) { + return ""; + } + + return " (aliased through '" + Joiner.on("' -> '").join(aliasProvider.getAliasChain()) + "')"; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java index 44f637f3e7..ffe2fcae76 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java @@ -372,7 +372,7 @@ public class SkylarkRuleImplementationFunctions { for (AbstractConfiguredTarget current : knownLabels) { builder.put( - current.getLabel(), + AliasProvider.getDependencyLabel(current), ImmutableList.copyOf(current.getProvider(FileProvider.class).getFilesToBuild())); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java b/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java index 6ea3edeab9..a832903d32 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java +++ b/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java @@ -14,107 +14,20 @@ package com.google.devtools.build.lib.rules.repository; -import com.google.common.collect.ImmutableCollection; -import com.google.common.collect.ImmutableList; -import com.google.devtools.build.lib.actions.Artifact; +import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.FileProvider; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.SkylarkProviders; import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; -import com.google.devtools.build.lib.analysis.config.BuildConfiguration; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.collect.nestedset.Order; -import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.rules.AliasConfiguredTarget; +import com.google.devtools.build.lib.rules.AliasProvider; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; -import com.google.devtools.build.lib.syntax.ClassObject; -import com.google.devtools.build.lib.syntax.SkylarkNestedSet; /** * Implementation for the bind rule. */ public class Bind implements RuleConfiguredTargetFactory { - /** - * This configured target pretends to be whatever type of target "actual" is, returning its - * transitive info providers and target, but returning the label for the //external target. - */ - private static class BindConfiguredTarget implements ConfiguredTarget, ClassObject { - - private Label label; - private ConfiguredTarget configuredTarget; - private BuildConfiguration config; - - BindConfiguredTarget(RuleContext ruleContext) { - label = ruleContext.getRule().getLabel(); - config = ruleContext.getConfiguration(); - // TODO(bazel-team): we should special case ConfiguredTargetFactory.createConfiguredTarget, - // not cast down here. - configuredTarget = (ConfiguredTarget) ruleContext.getPrerequisite("actual", Mode.TARGET); - } - - @Override - public <P extends TransitiveInfoProvider> P getProvider(Class<P> provider) { - return configuredTarget == null ? null : configuredTarget.getProvider(provider); - } - - @Override - public Label getLabel() { - return label; - } - - @Override - public Object get(String providerKey) { - return configuredTarget == null ? null : configuredTarget.get(providerKey); - } - - @Override - public Target getTarget() { - return configuredTarget == null ? null : configuredTarget.getTarget(); - } - - @Override - public BuildConfiguration getConfiguration() { - return config; - } - - /* ClassObject methods */ - - @Override - public Object getValue(String name) { - if (name.equals("label")) { - return getLabel(); - } else if (name.equals("files")) { - // A shortcut for files to build in Skylark. FileConfiguredTarget and RunleConfiguredTarget - // always has FileProvider and Error- and PackageGroupConfiguredTarget-s shouldn't be - // accessible in Skylark. - return SkylarkNestedSet.of(Artifact.class, configuredTarget == null - ? NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER) - : getProvider(FileProvider.class).getFilesToBuild()); - } - return configuredTarget == null ? null : configuredTarget.get(name); - } - - @SuppressWarnings("cast") - @Override - public ImmutableCollection<String> getKeys() { - ImmutableList.Builder<String> result = ImmutableList.<String>builder().add("label", "files"); - if (configuredTarget != null) { - result.addAll( - configuredTarget.getProvider(SkylarkProviders.class).getKeys()); - } - return result.build(); - } - - @Override - public String errorMessage(String name) { - // Use the default error message. - return null; - } - } - @Override public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { if (ruleContext.getPrerequisite("actual", Mode.TARGET) == null) { @@ -122,6 +35,10 @@ public class Bind implements RuleConfiguredTargetFactory { ruleContext.getLabel())); return null; } - return new BindConfiguredTarget(ruleContext); + + ConfiguredTarget actual = (ConfiguredTarget) ruleContext.getPrerequisite("actual", Mode.TARGET); + return new AliasConfiguredTarget(actual, + ImmutableMap.<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>of( + AliasProvider.class, AliasProvider.fromAliasRule(ruleContext.getLabel(), actual))); } } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java index 9bf225f1de..3917534afe 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ListMultimap; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment; @@ -57,8 +58,6 @@ import com.google.devtools.build.skyframe.SkyFunctionException; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; -import java.util.Set; - import javax.annotation.Nullable; /** @@ -212,9 +211,10 @@ public final class AspectFunction implements SkyFunction { new TargetAndConfiguration(target, key.getAspectConfiguration()); try { // Get the configuration targets that trigger this rule's configurable attributes. - Set<ConfigMatchingProvider> configConditions = ConfiguredTargetFunction.getConfigConditions( - target, env, resolver, originalTargetAndAspectConfiguration, - transitivePackages, transitiveRootCauses); + ImmutableMap<Label, ConfigMatchingProvider> configConditions = + ConfiguredTargetFunction.getConfigConditions( + target, env, resolver, originalTargetAndAspectConfiguration, + transitivePackages, transitiveRootCauses); if (configConditions == null) { // Those targets haven't yet been resolved. return null; @@ -299,7 +299,7 @@ public final class AspectFunction implements SkyFunction { ConfiguredAspectFactory aspectFactory, RuleConfiguredTarget associatedTarget, BuildConfiguration aspectConfiguration, - Set<ConfigMatchingProvider> configConditions, + ImmutableMap<Label, ConfigMatchingProvider> configConditions, ListMultimap<Attribute, ConfiguredTarget> directDeps, NestedSetBuilder<Package> transitivePackages) throws AspectFunctionException, InterruptedException { diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java index 6fb86c8dec..33d68bba44 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java @@ -17,7 +17,7 @@ import com.google.common.base.Function; import com.google.common.base.Verify; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.ListMultimap; @@ -54,7 +54,6 @@ import com.google.devtools.build.lib.packages.AspectClass; import com.google.devtools.build.lib.packages.AspectDefinition; import com.google.devtools.build.lib.packages.AspectParameters; import com.google.devtools.build.lib.packages.Attribute; -import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.NoSuchTargetException; import com.google.devtools.build.lib.packages.NoSuchThingException; @@ -76,9 +75,9 @@ import com.google.devtools.build.skyframe.ValueOrException; import com.google.devtools.build.skyframe.ValueOrException2; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -92,8 +91,8 @@ import javax.annotation.Nullable; final class ConfiguredTargetFunction implements SkyFunction { // This construction is a bit funky, but guarantees that the Object reference here is globally // unique. - static final Set<ConfigMatchingProvider> NO_CONFIG_CONDITIONS = - Collections.unmodifiableSet(ImmutableSet.<ConfigMatchingProvider>of()); + static final ImmutableMap<Label, ConfigMatchingProvider> NO_CONFIG_CONDITIONS = + ImmutableMap.<Label, ConfigMatchingProvider>of(); /** * Exception class that signals an error during the evaluation of a dependency. @@ -159,13 +158,7 @@ final class ConfiguredTargetFunction implements SkyFunction { new ConfiguredValueCreationException(e.getMessage())); } if (pkg.containsErrors()) { - if (target == null) { - throw new ConfiguredTargetFunctionException(new ConfiguredValueCreationException( - new BuildFileContainsErrorsException( - lc.getLabel().getPackageIdentifier()).getMessage())); - } else { - transitiveLoadingRootCauses.add(lc.getLabel()); - } + transitiveLoadingRootCauses.add(lc.getLabel()); } transitivePackages.add(pkg); // TODO(bazel-team): This is problematic - we create the right key, but then end up with a value @@ -180,7 +173,7 @@ final class ConfiguredTargetFunction implements SkyFunction { SkyframeDependencyResolver resolver = view.createDependencyResolver(env); try { // Get the configuration targets that trigger this rule's configurable attributes. - Set<ConfigMatchingProvider> configConditions = getConfigConditions( + ImmutableMap<Label, ConfigMatchingProvider> configConditions = getConfigConditions( ctgValue.getTarget(), env, resolver, ctgValue, transitivePackages, transitiveLoadingRootCauses); if (env.valuesMissing()) { @@ -265,7 +258,7 @@ final class ConfiguredTargetFunction implements SkyFunction { SkyframeDependencyResolver resolver, TargetAndConfiguration ctgValue, Aspect aspect, - Set<ConfigMatchingProvider> configConditions, + ImmutableMap<Label, ConfigMatchingProvider> configConditions, RuleClassProvider ruleClassProvider, BuildConfiguration hostConfiguration, NestedSetBuilder<Package> transitivePackages, @@ -686,8 +679,8 @@ final class ConfiguredTargetFunction implements SkyFunction { * dependency resolver, returns null. */ @Nullable - static Set<ConfigMatchingProvider> getConfigConditions(Target target, Environment env, - SkyframeDependencyResolver resolver, TargetAndConfiguration ctgValue, + static ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions(Target target, + Environment env, SkyframeDependencyResolver resolver, TargetAndConfiguration ctgValue, NestedSetBuilder<Package> transitivePackages, NestedSetBuilder<Label> transitiveLoadingRootCauses) throws DependencyEvaluationException { @@ -695,7 +688,7 @@ final class ConfiguredTargetFunction implements SkyFunction { return NO_CONFIG_CONDITIONS; } - ImmutableSet.Builder<ConfigMatchingProvider> configConditions = ImmutableSet.builder(); + Map<Label, ConfigMatchingProvider> configConditions = new LinkedHashMap<>(); // Collect the labels of the configured targets we need to resolve. ListMultimap<Attribute, LabelAndConfiguration> configLabelMap = ArrayListMultimap.create(); @@ -717,6 +710,10 @@ final class ConfiguredTargetFunction implements SkyFunction { // been computed yet. Collection<Dependency> configValueNames = resolver.resolveRuleLabels( ctgValue, configLabelMap, transitiveLoadingRootCauses); + if (env.valuesMissing()) { + return null; + } + // No need to get new configs from Skyframe - config_setting rules always use the current // target's config. @@ -744,7 +741,7 @@ final class ConfiguredTargetFunction implements SkyFunction { // The code above guarantees that value is non-null here. ConfigMatchingProvider provider = value.getProvider(ConfigMatchingProvider.class); if (provider != null) { - configConditions.add(provider); + configConditions.put(entry.getLabel(), provider); } else { // Not a valid provider for configuration conditions. String message = @@ -755,7 +752,7 @@ final class ConfiguredTargetFunction implements SkyFunction { } } - return configConditions.build(); + return ImmutableMap.copyOf(configConditions); } /*** @@ -813,7 +810,7 @@ final class ConfiguredTargetFunction implements SkyFunction { private ConfiguredTargetValue createConfiguredTarget(SkyframeBuildView view, Environment env, Target target, BuildConfiguration configuration, ListMultimap<Attribute, ConfiguredTarget> depValueMap, - Set<ConfigMatchingProvider> configConditions, + ImmutableMap<Label, ConfigMatchingProvider> configConditions, NestedSetBuilder<Package> transitivePackages) throws ConfiguredTargetFunctionException, InterruptedException { StoredEventHandler events = new StoredEventHandler(); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java index c33e599412..3289d173a6 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java @@ -15,7 +15,6 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; @@ -90,7 +89,7 @@ public class PostConfiguredTargetFunction implements SkyFunction { TargetAndConfiguration ctgValue = new TargetAndConfiguration(ct.getTarget(), ct.getConfiguration()); - Set<ConfigMatchingProvider> configConditions = + ImmutableMap<Label, ConfigMatchingProvider> configConditions = getConfigurableAttributeConditions(ctgValue, env); if (configConditions == null) { return null; @@ -131,10 +130,10 @@ public class PostConfiguredTargetFunction implements SkyFunction { * target, or null if not all dependencies have yet been SkyFrame-evaluated. */ @Nullable - private Set<ConfigMatchingProvider> getConfigurableAttributeConditions( + private ImmutableMap<Label, ConfigMatchingProvider> getConfigurableAttributeConditions( TargetAndConfiguration ctg, Environment env) { if (!(ctg.getTarget() instanceof Rule)) { - return ImmutableSet.of(); + return ImmutableMap.of(); } Rule rule = (Rule) ctg.getTarget(); RawAttributeMapper mapper = RawAttributeMapper.of(rule); @@ -150,10 +149,12 @@ public class PostConfiguredTargetFunction implements SkyFunction { if (env.valuesMissing()) { return null; } - ImmutableSet.Builder<ConfigMatchingProvider> conditions = ImmutableSet.builder(); - for (SkyValue ctValue : cts.values()) { - ConfiguredTarget ct = ((ConfiguredTargetValue) ctValue).getConfiguredTarget(); - conditions.add(Preconditions.checkNotNull(ct.getProvider(ConfigMatchingProvider.class))); + ImmutableMap.Builder<Label, ConfigMatchingProvider> conditions = ImmutableMap.builder(); + for (Map.Entry<SkyKey, SkyValue> entry : cts.entrySet()) { + Label label = ((ConfiguredTargetKey) entry.getKey().argument()).getLabel(); + ConfiguredTarget ct = ((ConfiguredTargetValue) entry.getValue()).getConfiguredTarget(); + conditions.put(label, Preconditions.checkNotNull( + ct.getProvider(ConfigMatchingProvider.class))); } return conditions.build(); } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java index 140dfbc9db..4231583217 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java @@ -473,7 +473,7 @@ public final class SkyframeBuildView { ConfiguredTarget createConfiguredTarget(Target target, BuildConfiguration configuration, CachingAnalysisEnvironment analysisEnvironment, ListMultimap<Attribute, ConfiguredTarget> prerequisiteMap, - Set<ConfigMatchingProvider> configConditions) throws InterruptedException { + ImmutableMap<Label, ConfigMatchingProvider> configConditions) throws InterruptedException { Preconditions.checkState(enableAnalysis, "Already in execution phase %s %s", target, configuration); Preconditions.checkNotNull(analysisEnvironment); diff --git a/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java b/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java index 9f89ecdb8b..239e2f12ad 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java @@ -16,7 +16,7 @@ package com.google.devtools.build.lib.analysis; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ListMultimap; import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider; import com.google.devtools.build.lib.analysis.util.AnalysisTestCase; @@ -94,7 +94,7 @@ public class DependencyResolverTest extends AnalysisTestCase { new TargetAndConfiguration(target, getTargetConfiguration()), getHostConfiguration(), aspect != null ? Aspect.forNative(aspect) : null, - ImmutableSet.<ConfigMatchingProvider>of()); + ImmutableMap.<Label, ConfigMatchingProvider>of()); } @SafeVarargs diff --git a/src/test/java/com/google/devtools/build/lib/analysis/select/ConfiguredAttributeMapperCommonTest.java b/src/test/java/com/google/devtools/build/lib/analysis/select/ConfiguredAttributeMapperCommonTest.java index 6023b6dbd8..361e7b9916 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/select/ConfiguredAttributeMapperCommonTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/select/ConfiguredAttributeMapperCommonTest.java @@ -13,9 +13,10 @@ // limitations under the License. package com.google.devtools.build.lib.analysis.select; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.ConfiguredAttributeMapper; import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.packages.AbstractAttributeMapper; import org.junit.Before; @@ -35,6 +36,6 @@ import org.junit.runners.JUnit4; public class ConfiguredAttributeMapperCommonTest extends AbstractAttributeMapperTest { @Before public final void createMapper() throws Exception { - mapper = ConfiguredAttributeMapper.of(rule, ImmutableSet.<ConfigMatchingProvider>of()); + mapper = ConfiguredAttributeMapper.of(rule, ImmutableMap.<Label, ConfigMatchingProvider>of()); } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/AliasTest.java b/src/test/java/com/google/devtools/build/lib/rules/AliasTest.java new file mode 100644 index 0000000000..04732114fe --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/rules/AliasTest.java @@ -0,0 +1,196 @@ +// Copyright 2016 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.rules; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.util.ActionsTestUtil; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.LicensesProvider; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.rules.cpp.CppCompilationContext; + +import org.junit.Test; + +/** + * Unit tests for the <code>alias</code> rule. + */ +public class AliasTest extends BuildViewTestCase { + @Test + public void smoke() throws Exception { + scratch.file("a/BUILD", + "cc_library(name='a', srcs=['a.cc'])", + "alias(name='b', actual='a')"); + + ConfiguredTarget b = getConfiguredTarget("//a:b"); + assertThat(b.getProvider(CppCompilationContext.class)).isNotNull(); + } + + @Test + public void visibilityIsOverriddenAndIsOkay() throws Exception { + scratch.file("a/BUILD", + "filegroup(name='a', visibility=['//b:__pkg__'])"); + scratch.file("b/BUILD", + "alias(name='b', actual='//a:a', visibility=['//visibility:public'])"); + scratch.file("c/BUILD", + "filegroup(name='c', srcs=['//b:b'])"); + + getConfiguredTarget("//c:c"); + } + + @Test + public void visibilityIsOverriddenAndIsError() throws Exception { + scratch.file("a/BUILD", + "filegroup(name='a', visibility=['//visibility:public'])"); + scratch.file("b/BUILD", + "alias(name='b', actual='//a:a', visibility=['//visibility:private'])"); + scratch.file("c/BUILD", + "filegroup(name='c', srcs=['//b:b'])"); + + reporter.removeHandler(failFastHandler); + getConfiguredTarget("//c:c"); + assertContainsEvent( + "Target '//a:a' is not visible from target '//c:c' (aliased through '//b:b')"); + } + + @Test + public void visibilityIsOverriddenAndIsErrorAfterMultipleAliases() throws Exception { + scratch.file("a/BUILD", + "filegroup(name='a', visibility=['//visibility:public'])"); + scratch.file("b/BUILD", + "alias(name='b', actual='//a:a', visibility=['//visibility:public'])"); + scratch.file("c/BUILD", + "alias(name='c', actual='//b:b', visibility=['//visibility:private'])"); + scratch.file("d/BUILD", + "filegroup(name='d', srcs=['//c:c'])"); + + reporter.removeHandler(failFastHandler); + getConfiguredTarget("//d:d"); + assertContainsEvent( + "Target '//a:a' is not visible from target '//d:d' (aliased through '//c:c' -> '//b:b')"); + } + + @Test + public void testAliasCycle() throws Exception { + scratch.file("a/BUILD", + "alias(name='a', actual=':b')", + "alias(name='b', actual=':c')", + "alias(name='c', actual=':a')", + "filegroup(name='d', srcs=[':c'])"); + + reporter.removeHandler(failFastHandler); + getConfiguredTarget("//a:d"); + assertContainsEvent("cycle in dependency graph"); + } + + @Test + public void testAliasedInvalidDependency() throws Exception { + scratch.file("a/BUILD", + "cc_library(name='a', deps=[':b'])", + "alias(name='b', actual=':c')", + "filegroup(name='c')"); + + reporter.removeHandler(failFastHandler); + getConfiguredTarget("//a:a"); + assertContainsEvent("filegroup rule '//a:c' (aliased through '//a:b') is misplaced here"); + } + + @Test + public void licensesAreCollected() throws Exception { + scratch.file("a/BUILD", + "filegroup(name='a', licenses=['unencumbered'])", + "alias(name='b', actual=':a', licenses=['restricted'])", + "filegroup(name='c', srcs=[':b'])"); + useConfiguration("--check_licenses"); + assertThat( + getConfiguredTarget("//a:c").getProvider(LicensesProvider.class).getTransitiveLicenses()) + .hasSize(2); + } + + @Test + public void passesTargetTypeCheck() throws Exception { + scratch.file("a/BUILD", + "cc_library(name='a', srcs=['a.cc'], deps=[':b'])", + "alias(name='b', actual=':c')", + "cc_library(name='c', srcs=['c.cc'])"); + + getConfiguredTarget("//a:a"); + } + + @Test + public void packageGroupInAlias() throws Exception { + scratch.file("a/BUILD", + "package_group(name='a', packages=['//a'])", + "alias(name='b', actual=':a')", + "filegroup(name='c', srcs=[':b'])"); + + reporter.removeHandler(failFastHandler); + getConfiguredTarget("//a:c"); + assertContainsEvent( + "in actual attribute of alias rule //a:b: package group '//a:a' is misplaced here"); + } + + @Test + public void aliasedFile() throws Exception { + scratch.file("a/BUILD", + "exports_files(['a'])", + "alias(name='b', actual='a')", + "filegroup(name='c', srcs=[':b'])"); + + ConfiguredTarget c = getConfiguredTarget("//a:c"); + assertThat(ActionsTestUtil.baseArtifactNames( + c.getProvider(FileProvider.class).getFilesToBuild())) + .containsExactly("a"); + } + + @Test + public void aliasedConfigSetting() throws Exception { + scratch.file("a/BUILD", + "filegroup(name='a', srcs=select({':b': ['f1'], '//conditions:default': ['f2']}))", + "alias(name='b', actual=':c')", + "config_setting(name='c', values={'define': 'foo=bar'})"); + + useConfiguration("--define=foo=bar"); + getConfiguredTarget("//a"); + } + + @Test + public void aliasedTestSuiteDep() throws Exception { + scratch.file("a/BUILD", + "sh_test(name='a', srcs=['a.sh'])"); + scratch.file("b/BUILD", + "alias(name='b', actual='//a:a', testonly=1)", + "test_suite(name='c', tests=[':b'])"); + + ConfiguredTarget c = getConfiguredTarget("//b:c"); + NestedSet<Artifact> runfiles = + c.getProvider(RunfilesProvider.class).getDataRunfiles().getAllArtifacts(); + assertThat(ActionsTestUtil.baseArtifactNames(runfiles)).contains("a.sh"); + } + + @Test + public void testRedirectChasing() throws Exception { + String toolsRepository = ruleClassProvider.getToolsRepository(); + scratch.file("a/BUILD", + "alias(name='cc', actual='" + toolsRepository + "//tools/cpp:toolchain')", + "cc_library(name='a', srcs=['a.cc'])"); + + useConfiguration("--crosstool_top=//a:cc"); + getConfiguredTarget("//a:a"); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD b/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD index 1d7724ff68..758194dabd 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD +++ b/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD @@ -16,6 +16,7 @@ java_test( "//src/main/java/com/google/devtools/build/lib/actions", "//src/main/java/com/google/devtools/build/lib/rules/cpp", "//src/main/java/com/google/devtools/build/skyframe", + "//src/test/java/com/google/devtools/build/lib:actions_testutil", "//src/test/java/com/google/devtools/build/lib:analysis_testutil", "//src/test/java/com/google/devtools/build/lib:packages_testutil", "//src/test/java/com/google/devtools/build/lib:testutil", |