diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis')
5 files changed, 177 insertions, 55 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java b/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java index fe97bfc3b4..bb6c38d9a4 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/Aspect.java @@ -22,6 +22,7 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.events.Location; import java.util.LinkedHashMap; import java.util.Map; @@ -88,6 +89,8 @@ public final class Aspect implements Iterable<TransitiveInfoProvider> { private final Map<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> providers = new LinkedHashMap<>(); private final Map<String, NestedSetBuilder<Artifact>> outputGroupBuilders = new TreeMap<>(); + private final ImmutableMap.Builder<String, Object> skylarkProviderBuilder = + ImmutableMap.builder(); private final String name; public Builder(String name) { @@ -103,6 +106,8 @@ public final class Aspect implements Iterable<TransitiveInfoProvider> { Preconditions.checkNotNull(value); AnalysisUtils.checkProvider(key); Preconditions.checkState(!providers.containsKey(key)); + Preconditions.checkArgument(!SkylarkProviders.class.equals(key), + "Do not provide SkylarkProviders directly"); providers.put(key, value); return this; } @@ -127,6 +132,12 @@ public final class Aspect implements Iterable<TransitiveInfoProvider> { return this; } + public Builder addSkylarkTransitiveInfo(String name, Object value, Location loc) { + // TODO(dslomov): add {@link RuleConfiguredTargetBuilder#checkSkylarkObjectSafe} + skylarkProviderBuilder.put(name, value); + return this; + } + public Aspect build() { if (!outputGroupBuilders.isEmpty()) { ImmutableMap.Builder<String, NestedSet<Artifact>> outputGroups = ImmutableMap.builder(); @@ -141,6 +152,11 @@ public final class Aspect implements Iterable<TransitiveInfoProvider> { addProvider(OutputGroupProvider.class, new OutputGroupProvider(outputGroups.build())); } + ImmutableMap<String, Object> skylarkProvidersMap = skylarkProviderBuilder.build(); + if (!skylarkProvidersMap.isEmpty()) { + providers.put(SkylarkProviders.class, new SkylarkProviders(skylarkProvidersMap)); + } + return new Aspect(name, ImmutableMap.copyOf(providers)); } } 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 14302ac179..e05dd596d9 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 @@ -42,6 +42,7 @@ import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection; import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider; 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.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; @@ -75,6 +76,7 @@ import com.google.devtools.build.lib.skyframe.SkyframeExecutor; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.util.RegexFilter; import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.WalkableGraph; import com.google.devtools.common.options.Option; @@ -450,18 +452,43 @@ public class BuildView { List<AspectKey> aspectKeys = new ArrayList<>(); for (String aspect : aspects) { - @SuppressWarnings("unchecked") - final Class<? extends ConfiguredAspectFactory> aspectFactoryClass = - (Class<? extends ConfiguredAspectFactory>) - ruleClassProvider.getAspectFactoryMap().get(aspect); - if (aspectFactoryClass != null) { + + // Syntax: label%aspect + int delimiterPosition = aspect.indexOf('%'); + if (delimiterPosition >= 0) { + PackageIdentifier bzlFile; + try { + bzlFile = + PackageIdentifier.create( + PackageIdentifier.DEFAULT_REPOSITORY, + new PathFragment(aspect.substring(0, delimiterPosition))); + } catch (LabelSyntaxException e) { + throw new ViewCreationFailedException("Error", e); + } + + String skylarkFunctionName = aspect.substring(delimiterPosition + 1); for (ConfiguredTargetKey targetSpec : targetSpecs) { aspectKeys.add( - AspectValue.createAspectKey( - targetSpec.getLabel(), targetSpec.getConfiguration(), aspectFactoryClass)); + AspectValue.createSkylarkAspectKey( + targetSpec.getLabel(), + targetSpec.getConfiguration(), + bzlFile, + skylarkFunctionName)); } } else { - throw new ViewCreationFailedException("Aspect '" + aspect + "' is unknown"); + @SuppressWarnings("unchecked") + final Class<? extends ConfiguredAspectFactory> aspectFactoryClass = + (Class<? extends ConfiguredAspectFactory>) + ruleClassProvider.getAspectFactoryMap().get(aspect); + if (aspectFactoryClass != null) { + for (ConfiguredTargetKey targetSpec : targetSpecs) { + aspectKeys.add( + AspectValue.createAspectKey( + targetSpec.getLabel(), targetSpec.getConfiguration(), aspectFactoryClass)); + } + } else { + throw new ViewCreationFailedException("Aspect '" + aspect + "' is unknown"); + } } } 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 6d97e86c42..a8cc9e4932 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 @@ -286,12 +286,14 @@ public final class ConfiguredTargetFactory { * {@code aspectFactory} should call one of the error reporting methods of {@link RuleContext}. */ public Aspect createAspect( - AnalysisEnvironment env, RuleConfiguredTarget associatedTarget, + AnalysisEnvironment env, + RuleConfiguredTarget associatedTarget, ConfiguredAspectFactory aspectFactory, AspectParameters aspectParameters, ListMultimap<Attribute, ConfiguredTarget> prerequisiteMap, Set<ConfigMatchingProvider> configConditions, - BuildConfiguration hostConfiguration) { + BuildConfiguration hostConfiguration) + throws InterruptedException { RuleContext.Builder builder = new RuleContext.Builder(env, associatedTarget.getTarget(), associatedTarget.getConfiguration(), 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 9bb9365d80..d8614597a4 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 @@ -22,7 +22,6 @@ import com.google.common.collect.UnmodifiableIterator; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider; import com.google.devtools.build.lib.analysis.config.RunUnder; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.OutputFile; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.rules.SkylarkApiProvider; @@ -131,20 +130,14 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { providers.addAll(base.providers.keySet()); // Merge output group providers. - OutputGroupProvider baseOutputGroupProvider = base.getProvider(OutputGroupProvider.class); - List<OutputGroupProvider> outputGroupProviders = new ArrayList<>(); - if (baseOutputGroupProvider != null) { - outputGroupProviders.add(baseOutputGroupProvider); - } + List<OutputGroupProvider> outputGroupProviders = + getAllProviders(base, aspects, OutputGroupProvider.class); + OutputGroupProvider mergedOutputGroupProvider = OutputGroupProvider.merge(outputGroupProviders); - for (Aspect aspect : aspects) { - final OutputGroupProvider aspectProvider = aspect.getProvider(OutputGroupProvider.class); - if (aspectProvider == null) { - continue; - } - outputGroupProviders.add(aspectProvider); - } - OutputGroupProvider outputGroupProvider = OutputGroupProvider.merge(outputGroupProviders); + // Merge Skylark providers. + List<SkylarkProviders> skylarkProviders = + getAllProviders(base, aspects, SkylarkProviders.class); + SkylarkProviders mergedSkylarkProviders = SkylarkProviders.merge(skylarkProviders); // Validate that all other providers are only provided once. for (Aspect aspect : aspects) { @@ -153,13 +146,17 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { if (OutputGroupProvider.class.equals(aClass)) { continue; } + if (SkylarkProviders.class.equals(aClass)) { + continue; + } if (!providers.add(aClass)) { throw new IllegalStateException("Provider " + aClass + " provided twice"); } } } - if (baseOutputGroupProvider == outputGroupProvider) { + if (base.getProvider(OutputGroupProvider.class) == mergedOutputGroupProvider + && base.getProvider(SkylarkProviders.class) == mergedSkylarkProviders) { this.providers = base.providers; } else { ImmutableMap.Builder<Class<? extends TransitiveInfoProvider>, Object> builder = @@ -168,9 +165,17 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { if (OutputGroupProvider.class.equals(aClass)) { continue; } + if (SkylarkProviders.class.equals(aClass)) { + continue; + } builder.put(aClass, base.providers.get(aClass)); } - builder.put(OutputGroupProvider.class, outputGroupProvider); + if (mergedOutputGroupProvider != null) { + builder.put(OutputGroupProvider.class, mergedOutputGroupProvider); + } + if (mergedSkylarkProviders != null) { + builder.put(SkylarkProviders.class, skylarkProviders); + } this.providers = builder.build(); } this.mandatoryStampFiles = base.mandatoryStampFiles; @@ -178,6 +183,26 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { this.aspects = ImmutableList.copyOf(aspects); } + private static <T extends TransitiveInfoProvider> List<T> getAllProviders( + RuleConfiguredTarget base, + Iterable<Aspect> aspects, + Class<T> providerClass) { + T baseProvider = base.getProvider(providerClass); + List<T> providers = new ArrayList<>(); + if (baseProvider != null) { + providers.add(baseProvider); + } + + for (Aspect aspect : aspects) { + final T aspectProvider = aspect.getProvider(providerClass); + if (aspectProvider == null) { + continue; + } + providers.add(aspectProvider); + } + return providers; + } + /** * The configuration conditions that trigger this rule's configurable attributes. */ @@ -208,7 +233,7 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { */ @Override public Object get(String providerKey) { - return getProvider(SkylarkProviders.class).skylarkProviders.get(providerKey); + return getProvider(SkylarkProviders.class).getValue(providerKey); } public ImmutableList<Artifact> getMandatoryStampFiles() { @@ -220,33 +245,6 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { return (Rule) super.getTarget(); } - /** - * A helper class for transitive infos provided by Skylark rule implementations. - */ - @Immutable - public static final class SkylarkProviders implements TransitiveInfoProvider { - private final ImmutableMap<String, Object> skylarkProviders; - - private SkylarkProviders(ImmutableMap<String, Object> skylarkProviders) { - Preconditions.checkNotNull(skylarkProviders); - this.skylarkProviders = skylarkProviders; - } - - /** - * Returns the keys for the Skylark providers. - */ - public ImmutableCollection<String> getKeys() { - return skylarkProviders.keySet(); - } - - /** - * Returns a Skylark provider; "key" must be one from {@link #getKeys()}. - */ - public Object getValue(String key) { - return skylarkProviders.get(key); - } - } - @Override public UnmodifiableIterator<TransitiveInfoProvider> iterator() { Map<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> allProviders = @@ -273,6 +271,6 @@ public final class RuleConfiguredTarget extends AbstractConfiguredTarget { @Override public ImmutableCollection<String> getKeys() { return ImmutableList.<String>builder().addAll(super.getKeys()) - .addAll(getProvider(SkylarkProviders.class).skylarkProviders.keySet()).build(); + .addAll(getProvider(SkylarkProviders.class).getKeys()).build(); } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SkylarkProviders.java b/src/main/java/com/google/devtools/build/lib/analysis/SkylarkProviders.java new file mode 100644 index 0000000000..d4746c4659 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/SkylarkProviders.java @@ -0,0 +1,79 @@ +// Copyright 2014 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.analysis; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A helper class for transitive infos provided by Skylark rule implementations. + */ +@Immutable +public final class SkylarkProviders implements TransitiveInfoProvider { + private final ImmutableMap<String, Object> skylarkProviders; + + SkylarkProviders(ImmutableMap<String, Object> skylarkProviders) { + Preconditions.checkNotNull(skylarkProviders); + this.skylarkProviders = skylarkProviders; + } + + /** + * Returns the keys for the Skylark providers. + */ + public ImmutableCollection<String> getKeys() { + return skylarkProviders.keySet(); + } + + /** + * Returns a Skylark provider; "key" must be one from {@link #getKeys()}. + */ + public Object getValue(String key) { + return skylarkProviders.get(key); + } + + /** + * Merges skylark providers. The set of providers must be disjoint. + * + * @param providers providers to merge {@code this} with. + */ + + public static SkylarkProviders merge(List<SkylarkProviders> providers) { + if (providers.size() == 0) { + return null; + } + if (providers.size() == 1) { + return providers.get(0); + } + + ImmutableMap.Builder<String, Object> resultBuilder = new ImmutableMap.Builder<>(); + Set<String> seenKeys = new HashSet<>(); + for (SkylarkProviders provider : providers) { + for (String key : provider.skylarkProviders.keySet()) { + if (!seenKeys.add(key)) { + // TODO(dslomov): add better diagnostics. + throw new IllegalStateException("Skylark provider " + key + " provided twice"); + } + + resultBuilder.put(key, provider.getValue(key)); + } + } + return new SkylarkProviders(resultBuilder.build()); + } +} |