blob: 0dcbc678d098a56f6410bef405618f8c8549df12 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.analysis;
16
Janak Ramakrishnan7857c792016-03-21 08:35:35 +000017import com.google.common.annotations.VisibleForTesting;
Yun Peng5c34e962016-02-22 15:13:19 +000018import com.google.common.base.Joiner;
Googler59480b92016-07-22 17:06:40 +000019import com.google.common.base.Optional;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020import com.google.common.base.Predicate;
Yun Pengefd7ca12016-03-03 13:14:38 +000021import com.google.common.base.Predicates;
Cal Peyserf296e872016-05-03 17:36:54 +000022import com.google.common.collect.ImmutableBiMap;
Florian Weikert082c0542015-08-06 10:24:29 +000023import com.google.common.collect.ImmutableCollection;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010024import com.google.common.collect.ImmutableList;
25import com.google.common.collect.ImmutableListMultimap;
26import com.google.common.collect.ImmutableMap;
27import com.google.common.collect.ImmutableSet;
Manuel Klimek6d9fb362015-04-30 12:50:55 +000028import com.google.common.collect.ImmutableSortedSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.common.collect.Iterables;
30import com.google.common.collect.ListMultimap;
31import com.google.common.collect.Multimaps;
32import com.google.common.collect.Sets;
33import com.google.devtools.build.lib.actions.Action;
Rumou Duan33bab462016-04-25 17:55:12 +000034import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035import com.google.devtools.build.lib.actions.ActionOwner;
36import com.google.devtools.build.lib.actions.ActionRegistry;
37import com.google.devtools.build.lib.actions.Artifact;
38import com.google.devtools.build.lib.actions.ArtifactOwner;
39import com.google.devtools.build.lib.actions.Root;
40import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.PrerequisiteValidator;
Vladimir Moskvab4ad1542016-09-29 13:05:48 +000041import com.google.devtools.build.lib.analysis.LocationExpander.Options;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010042import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
43import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
Ulf Adamsc272e0f2015-04-22 19:56:21 +000044import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
46import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
Greg Estren66cadd32016-08-05 21:07:02 +000047import com.google.devtools.build.lib.analysis.config.BuildOptions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010048import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
Florian Weikert3f8aac92015-09-07 12:06:02 +000049import com.google.devtools.build.lib.analysis.config.FragmentCollection;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000050import com.google.devtools.build.lib.cmdline.Label;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010051import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap;
52import com.google.devtools.build.lib.collect.nestedset.NestedSet;
53import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
54import com.google.devtools.build.lib.events.Event;
Klaus Aehlig16a107d2017-05-31 18:02:43 +020055import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010056import com.google.devtools.build.lib.events.Location;
Dmitry Lomov15756522016-12-16 16:52:37 +000057import com.google.devtools.build.lib.packages.AspectDescriptor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058import com.google.devtools.build.lib.packages.Attribute;
59import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
60import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
61import com.google.devtools.build.lib.packages.AttributeMap;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000062import com.google.devtools.build.lib.packages.BuildType;
Michael Staibb51251e2015-09-29 23:31:51 +000063import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010064import com.google.devtools.build.lib.packages.FileTarget;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000065import com.google.devtools.build.lib.packages.FilesetEntry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010066import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
dslomovde965ac2017-07-31 21:07:51 +020067import com.google.devtools.build.lib.packages.Info;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010068import com.google.devtools.build.lib.packages.InputFile;
dslomovde965ac2017-07-31 21:07:51 +020069import com.google.devtools.build.lib.packages.NativeProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010070import com.google.devtools.build.lib.packages.OutputFile;
71import com.google.devtools.build.lib.packages.PackageSpecification;
72import com.google.devtools.build.lib.packages.RawAttributeMapper;
dslomovc13bb392017-08-02 23:29:54 +020073import com.google.devtools.build.lib.packages.RequiredProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074import com.google.devtools.build.lib.packages.Rule;
75import com.google.devtools.build.lib.packages.RuleClass;
Chris Parsons4dfb22c2016-05-23 17:39:42 +000076import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010077import com.google.devtools.build.lib.packages.RuleErrorConsumer;
78import com.google.devtools.build.lib.packages.Target;
79import com.google.devtools.build.lib.packages.TargetUtils;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010080import com.google.devtools.build.lib.rules.fileset.FilesetProvider;
81import com.google.devtools.build.lib.shell.ShellUtils;
82import com.google.devtools.build.lib.syntax.EvalException;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000083import com.google.devtools.build.lib.syntax.Type;
Michael Staiba751f922017-02-14 15:50:04 +000084import com.google.devtools.build.lib.syntax.Type.LabelClass;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085import com.google.devtools.build.lib.util.FileTypeSet;
Greg Estrend5353252016-08-11 22:13:31 +000086import com.google.devtools.build.lib.util.OrderedSetMultimap;
Mark Schaller6df81792015-12-10 18:47:47 +000087import com.google.devtools.build.lib.util.Preconditions;
Googlere49cd592016-07-29 19:32:38 +000088import com.google.devtools.build.lib.util.StringUtil;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010089import com.google.devtools.build.lib.vfs.FileSystemUtils;
90import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010091import java.util.ArrayList;
92import java.util.Collection;
hlopkoa4778052017-05-26 11:37:28 +020093import java.util.Collections;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094import java.util.HashMap;
95import java.util.HashSet;
lberki3c1c8e92017-07-13 12:25:47 +020096import java.util.LinkedHashMap;
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +000097import java.util.LinkedHashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010098import java.util.List;
99import java.util.Map;
100import java.util.Set;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100101import javax.annotation.Nullable;
102
103/**
Lukacs Berki2300cd62016-05-19 11:06:37 +0000104 * The totality of data available during the analysis of a rule.
Janak Ramakrishnan81c5bd82016-03-22 20:07:43 +0000105 *
106 * <p>These objects should not outlast the analysis phase. Do not pass them to {@link Action}
107 * objects or other persistent objects. There are internal tests to ensure that RuleContext objects
108 * are not persisted that check the name of this class, so update those tests if you change this
109 * class's name.
Lukacs Berki2300cd62016-05-19 11:06:37 +0000110 *
ulfjack26d0e492017-08-07 13:42:33 +0200111 * @see com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100112 */
113public final class RuleContext extends TargetContext
114 implements ActionConstructionContext, ActionRegistry, RuleErrorConsumer {
Carmi Grushko33aa3062016-11-11 02:45:29 +0000115
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100116 /**
117 * The configured version of FilesetEntry.
118 */
119 @Immutable
120 public static final class ConfiguredFilesetEntry {
121 private final FilesetEntry entry;
122 private final TransitiveInfoCollection src;
123 private final ImmutableList<TransitiveInfoCollection> files;
124
125 ConfiguredFilesetEntry(FilesetEntry entry, TransitiveInfoCollection src) {
126 this.entry = entry;
127 this.src = src;
128 this.files = null;
129 }
130
131 ConfiguredFilesetEntry(FilesetEntry entry, ImmutableList<TransitiveInfoCollection> files) {
132 this.entry = entry;
133 this.src = null;
134 this.files = files;
135 }
136
137 public FilesetEntry getEntry() {
138 return entry;
139 }
140
141 public TransitiveInfoCollection getSrc() {
142 return src;
143 }
144
145 /**
146 * Targets from FilesetEntry.files, or null if the user omitted it.
147 */
148 @Nullable
Ulf Adams10993fe2016-04-19 12:55:12 +0000149 public ImmutableList<TransitiveInfoCollection> getFiles() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100150 return files;
151 }
152 }
153
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000154 private static final String HOST_CONFIGURATION_PROGRESS_TAG = "for host";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100155
156 private final Rule rule;
Dmitry Lomov15756522016-12-16 16:52:37 +0000157 private final ImmutableList<AspectDescriptor> aspectDescriptors;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100158 private final ListMultimap<String, ConfiguredTarget> targetMap;
159 private final ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap;
Lukacs Berki7894c182016-05-10 12:07:01 +0000160 private final ImmutableMap<Label, ConfigMatchingProvider> configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000161 private final AspectAwareAttributeMapper attributes;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100162 private final ImmutableSet<String> features;
Michael Staib8824d5e2016-01-20 21:37:05 +0000163 private final String ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000164 private final BuildConfiguration hostConfiguration;
Michael Staibb51251e2015-09-29 23:31:51 +0000165 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
Greg Estrenc5a352f2015-11-13 17:25:36 +0000166 private final Class<? extends BuildConfiguration.Fragment> universalFragment;
Florian Weikertb8a6a942015-09-25 12:36:08 +0000167 private final ErrorReporter reporter;
John Cater13263f72017-05-24 19:06:47 +0200168 @Nullable private final ToolchainContext toolchainContext;
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000169
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100170 private ActionOwner actionOwner;
171
172 /* lazily computed cache for Make variables, computed from the above. See get... method */
173 private transient ConfigurationMakeVariableContext configurationMakeVariableContext = null;
174
Dmitry Lomovace678e2015-12-16 15:10:20 +0000175 private RuleContext(
176 Builder builder,
Nathan Harmatafcb17112016-04-13 16:56:58 +0000177 AttributeMap attributes,
Dmitry Lomovace678e2015-12-16 15:10:20 +0000178 ListMultimap<String, ConfiguredTarget> targetMap,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100179 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap,
Lukacs Berki7894c182016-05-10 12:07:01 +0000180 ImmutableMap<Label, ConfigMatchingProvider> configConditions,
Greg Estrenc5a352f2015-11-13 17:25:36 +0000181 Class<? extends BuildConfiguration.Fragment> universalFragment,
Michael Staib8824d5e2016-01-20 21:37:05 +0000182 String ruleClassNameForLogging,
John Cater13263f72017-05-24 19:06:47 +0200183 ImmutableMap<String, Attribute> aspectAttributes,
184 @Nullable ToolchainContext toolchainContext) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100185 super(builder.env, builder.rule, builder.configuration, builder.prerequisiteMap.get(null),
186 builder.visibility);
187 this.rule = builder.rule;
Dmitry Lomov15756522016-12-16 16:52:37 +0000188 this.aspectDescriptors = builder.aspectDescriptors;
Michael Staibb51251e2015-09-29 23:31:51 +0000189 this.configurationFragmentPolicy = builder.configurationFragmentPolicy;
Greg Estrenc5a352f2015-11-13 17:25:36 +0000190 this.universalFragment = universalFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100191 this.targetMap = targetMap;
192 this.filesetEntryMap = filesetEntryMap;
193 this.configConditions = configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000194 this.attributes = new AspectAwareAttributeMapper(attributes, aspectAttributes);
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000195 this.features = getEnabledFeatures();
Michael Staib8824d5e2016-01-20 21:37:05 +0000196 this.ruleClassNameForLogging = ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000197 this.hostConfiguration = builder.hostConfiguration;
Florian Weikertb8a6a942015-09-25 12:36:08 +0000198 reporter = builder.reporter;
John Cater13263f72017-05-24 19:06:47 +0200199 this.toolchainContext = toolchainContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100200 }
201
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000202 private ImmutableSet<String> getEnabledFeatures() {
203 Set<String> globallyEnabled = new HashSet<>();
204 Set<String> globallyDisabled = new HashSet<>();
205 parseFeatures(getConfiguration().getDefaultFeatures(), globallyEnabled, globallyDisabled);
Googler21da7262015-09-19 00:29:50 +0000206 for (ImmutableMap.Entry<Class<? extends Fragment>, Fragment> entry :
207 getConfiguration().getAllFragments().entrySet()) {
Michael Staibff66c192016-01-14 22:40:37 +0000208 if (isLegalFragment(entry.getKey())) {
Googler21da7262015-09-19 00:29:50 +0000209 globallyEnabled.addAll(entry.getValue().configurationEnabledFeatures(this));
210 }
211 }
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000212 Set<String> packageEnabled = new HashSet<>();
213 Set<String> packageDisabled = new HashSet<>();
214 parseFeatures(getRule().getPackage().getFeatures(), packageEnabled, packageDisabled);
215 Set<String> packageFeatures =
216 Sets.difference(Sets.union(globallyEnabled, packageEnabled), packageDisabled);
217 Set<String> ruleFeatures = packageFeatures;
218 if (attributes().has("features", Type.STRING_LIST)) {
219 Set<String> ruleEnabled = new HashSet<>();
220 Set<String> ruleDisabled = new HashSet<>();
221 parseFeatures(attributes().get("features", Type.STRING_LIST), ruleEnabled, ruleDisabled);
222 ruleFeatures = Sets.difference(Sets.union(packageFeatures, ruleEnabled), ruleDisabled);
223 }
224 return ImmutableSortedSet.copyOf(Sets.difference(ruleFeatures, globallyDisabled));
225 }
226
227 private void parseFeatures(Iterable<String> features, Set<String> enabled, Set<String> disabled) {
228 for (String feature : features) {
229 if (feature.startsWith("-")) {
230 disabled.add(feature.substring(1));
231 } else if (feature.equals("no_layering_check")) {
232 // TODO(bazel-team): Remove once we do not have BUILD files left that contain
233 // 'no_layering_check'.
234 disabled.add(feature.substring(3));
235 } else {
236 enabled.add(feature);
237 }
238 }
239 }
240
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100241 @Override
242 public Rule getRule() {
243 return rule;
244 }
245
246 /**
Michael Staib8824d5e2016-01-20 21:37:05 +0000247 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
248 */
249 public String getRuleClassNameForLogging() {
250 return ruleClassNameForLogging;
251 }
252
253 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +0000254 * Returns the workspace name for the rule.
255 */
256 public String getWorkspaceName() {
kchodorow85ae1902017-04-22 15:07:22 -0400257 return rule.getRepository().strippedName();
Kristina Chodorow91876f02015-02-27 17:14:12 +0000258 }
259
260 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100261 * The configuration conditions that trigger this rule's configurable attributes.
262 */
Lukacs Berki7894c182016-05-10 12:07:01 +0000263 ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100264 return configConditions;
265 }
266
267 /**
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000268 * Returns the host configuration for this rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100269 */
270 public BuildConfiguration getHostConfiguration() {
Greg Estren9eb1cf02015-06-26 22:18:35 +0000271 return hostConfiguration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100272 }
273
274 /**
Dmitry Lomovace678e2015-12-16 15:10:20 +0000275 * Attributes from aspects.
276 */
277 public ImmutableMap<String, Attribute> getAspectAttributes() {
Greg Estren7f534232016-12-01 21:38:25 +0000278 return attributes.getAspectAttributes();
Dmitry Lomovace678e2015-12-16 15:10:20 +0000279 }
280
281 /**
Dmitry Lomov503c2f72017-02-23 08:55:47 +0000282 * All aspects applied to the rule.
283 */
284 public ImmutableList<AspectDescriptor> getAspectDescriptors() {
285 return aspectDescriptors;
286 }
287
288 /**
Greg Estren7f534232016-12-01 21:38:25 +0000289 * Accessor for the attributes of the rule and its aspects.
290 *
291 * <p>The rule's native attributes can be queried both on their structure / existence and values
292 * Aspect attributes can only be queried on their structure.
293 *
294 * <p>This should be the sole interface for reading rule/aspect attributes in {@link RuleContext}.
295 * Don't expose other access points through new public methods.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100296 */
297 public AttributeMap attributes() {
298 return attributes;
299 }
300
301 /**
302 * Returns whether this instance is known to have errors at this point during analysis. Do not
303 * call this method after the initializationHook has returned.
304 */
305 public boolean hasErrors() {
306 return getAnalysisEnvironment().hasErrors();
307 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000308
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000309 /**
310 * No-op if {@link #hasErrors} is false, throws {@link RuleErrorException} if it is true.
311 * This provides a convenience to early-exit of configured target creation if there are errors.
312 */
313 public void assertNoErrors() throws RuleErrorException {
314 if (hasErrors()) {
315 throw new RuleErrorException();
316 }
317 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100318
319 /**
320 * Returns an immutable map from attribute name to list of configured targets for that attribute.
321 */
322 public ListMultimap<String, ? extends TransitiveInfoCollection> getConfiguredTargetMap() {
323 return targetMap;
324 }
325
326 /**
327 * Returns an immutable map from attribute name to list of fileset entries.
328 */
329 public ListMultimap<String, ConfiguredFilesetEntry> getFilesetEntryMap() {
330 return filesetEntryMap;
331 }
332
333 @Override
334 public ActionOwner getActionOwner() {
335 if (actionOwner == null) {
Dmitry Lomov15756522016-12-16 16:52:37 +0000336 actionOwner = createActionOwner(rule, aspectDescriptors, getConfiguration());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100337 }
338 return actionOwner;
339 }
340
341 /**
342 * Returns a configuration fragment for this this target.
343 */
344 @Nullable
Florian Weikert3f8aac92015-09-07 12:06:02 +0000345 public <T extends Fragment> T getFragment(Class<T> fragment, ConfigurationTransition config) {
Florian Weikertd2a24612015-09-07 14:35:23 +0000346 return getFragment(fragment, fragment.getSimpleName(), "", config);
347 }
348
349 @Nullable
350 protected <T extends Fragment> T getFragment(Class<T> fragment, String name,
351 String additionalErrorMessage, ConfigurationTransition config) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100352 // TODO(bazel-team): The fragments can also be accessed directly through BuildConfiguration.
353 // Can we lock that down somehow?
Florian Weikert3f8aac92015-09-07 12:06:02 +0000354 Preconditions.checkArgument(isLegalFragment(fragment, config),
Florian Weikertd2a24612015-09-07 14:35:23 +0000355 "%s has to declare '%s' as a required fragment "
356 + "in %s configuration in order to access it.%s",
Michael Staib8824d5e2016-01-20 21:37:05 +0000357 getRuleClassNameForLogging(), name, FragmentCollection.getConfigurationName(config),
Florian Weikertd2a24612015-09-07 14:35:23 +0000358 additionalErrorMessage);
Florian Weikert1c2eeac2015-10-28 10:00:53 +0000359 return getConfiguration(config).getFragment(fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100360 }
361
Florian Weikert082c0542015-08-06 10:24:29 +0000362 @Nullable
Florian Weikert3f8aac92015-09-07 12:06:02 +0000363 public <T extends Fragment> T getFragment(Class<T> fragment) {
364 // NONE means target configuration.
365 return getFragment(fragment, ConfigurationTransition.NONE);
Florian Weikert082c0542015-08-06 10:24:29 +0000366 }
367
Florian Weikert3f8aac92015-09-07 12:06:02 +0000368 @Nullable
369 public Fragment getSkylarkFragment(String name, ConfigurationTransition config) {
Florian Weikert1c2eeac2015-10-28 10:00:53 +0000370 Class<? extends Fragment> fragmentClass =
371 getConfiguration(config).getSkylarkFragmentByName(name);
Florian Weikertd2a24612015-09-07 14:35:23 +0000372 if (fragmentClass == null) {
373 return null;
374 }
375 return getFragment(fragmentClass, name,
376 String.format(
377 " Please update the '%1$sfragments' argument of the rule definition "
378 + "(for example: %1$sfragments = [\"%2$s\"])",
379 (config == ConfigurationTransition.HOST) ? "host_" : "", name),
380 config);
Florian Weikert3f8aac92015-09-07 12:06:02 +0000381 }
382
383 public ImmutableCollection<String> getSkylarkFragmentNames(ConfigurationTransition config) {
384 return getConfiguration(config).getSkylarkFragmentNames();
385 }
386
387 public <T extends Fragment> boolean isLegalFragment(
388 Class<T> fragment, ConfigurationTransition config) {
Greg Estrenc5a352f2015-11-13 17:25:36 +0000389 return fragment == universalFragment
390 || configurationFragmentPolicy.isLegalConfigurationFragment(fragment, config);
Florian Weikert082c0542015-08-06 10:24:29 +0000391 }
392
Ulf Adamsea11fc52015-08-04 14:23:58 +0000393 public <T extends Fragment> boolean isLegalFragment(Class<T> fragment) {
Florian Weikert3f8aac92015-09-07 12:06:02 +0000394 // NONE means target configuration.
395 return isLegalFragment(fragment, ConfigurationTransition.NONE);
396 }
Florian Weikertd2a24612015-09-07 14:35:23 +0000397
Florian Weikert3f8aac92015-09-07 12:06:02 +0000398 protected BuildConfiguration getConfiguration(ConfigurationTransition config) {
399 return config.equals(ConfigurationTransition.HOST) ? hostConfiguration : getConfiguration();
Ulf Adamsea11fc52015-08-04 14:23:58 +0000400 }
401
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100402 @Override
403 public ArtifactOwner getOwner() {
404 return getAnalysisEnvironment().getOwner();
405 }
406
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000407 public ImmutableList<Artifact> getBuildInfo(BuildInfoKey key) throws InterruptedException {
Googler38ad0bf2016-07-01 05:00:14 +0000408 return getAnalysisEnvironment().getBuildInfo(this, key, getConfiguration());
Ulf Adamsc272e0f2015-04-22 19:56:21 +0000409 }
410
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000411 @VisibleForTesting
Carmi Grushko33aa3062016-11-11 02:45:29 +0000412 public static ActionOwner createActionOwner(
413 Rule rule,
Dmitry Lomov15756522016-12-16 16:52:37 +0000414 ImmutableList<AspectDescriptor> aspectDescriptors,
Carmi Grushko33aa3062016-11-11 02:45:29 +0000415 BuildConfiguration configuration) {
Carmi Grushko4665e702016-11-09 21:51:27 +0000416 return ActionOwner.create(
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000417 rule.getLabel(),
Dmitry Lomov15756522016-12-16 16:52:37 +0000418 aspectDescriptors,
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000419 rule.getLocation(),
420 configuration.getMnemonic(),
421 rule.getTargetKind(),
422 configuration.checksum(),
Klaus Aehligce1c36d2017-07-13 13:22:44 +0200423 configuration,
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000424 configuration.isHostConfiguration() ? HOST_CONFIGURATION_PROGRESS_TAG : null);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100425 }
426
427 @Override
Rumou Duan33bab462016-04-25 17:55:12 +0000428 public void registerAction(ActionAnalysisMetadata... action) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100429 getAnalysisEnvironment().registerAction(action);
430 }
431
432 /**
433 * Convenience function for subclasses to report non-attribute-specific
434 * errors in the current rule.
435 */
436 @Override
437 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000438 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100439 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000440
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000441 /**
442 * Convenience function to report non-attribute-specific errors in the current rule and then
443 * throw a {@link RuleErrorException}, immediately exiting the build invocation. Alternatively,
444 * invoke {@link #ruleError} instead to collect additional error information before ending the
445 * invocation.
446 */
447 public void throwWithRuleError(String message) throws RuleErrorException {
448 reporter.ruleError(message);
449 throw new RuleErrorException();
450 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100451
452 /**
453 * Convenience function for subclasses to report non-attribute-specific
454 * warnings in the current rule.
455 */
456 @Override
457 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000458 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100459 }
460
461 /**
462 * Convenience function for subclasses to report attribute-specific errors in
463 * the current rule.
464 *
465 * <p>If the name of the attribute starts with <code>$</code>
466 * it is replaced with a string <code>(an implicit dependency)</code>.
467 */
468 @Override
469 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000470 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100471 }
472
473 /**
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000474 * Convenience function to report attribute-specific errors in the current rule, and then throw a
475 * {@link RuleErrorException}, immediately exiting the build invocation. Alternatively, invoke
476 * {@link #attributeError} instead to collect additional error information before ending the
477 * invocation.
478 *
479 * <p>If the name of the attribute starts with <code>$</code>
480 * it is replaced with a string <code>(an implicit dependency)</code>.
481 */
Chris Parsonsf6a45fd2016-06-15 19:32:34 +0000482 public RuleErrorException throwWithAttributeError(String attrName, String message)
483 throws RuleErrorException {
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000484 reporter.attributeError(attrName, message);
485 throw new RuleErrorException();
486 }
487
488 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100489 * Like attributeError, but does not mark the configured target as errored.
490 *
491 * <p>If the name of the attribute starts with <code>$</code>
492 * it is replaced with a string <code>(an implicit dependency)</code>.
493 */
494 @Override
495 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000496 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100497 }
498
499 /**
500 * Returns an artifact beneath the root of either the "bin" or "genfiles"
501 * tree, whose path is based on the name of this target and the current
502 * configuration. The choice of which tree to use is based on the rule with
503 * which this target (which must be an OutputFile or a Rule) is associated.
504 */
505 public Artifact createOutputArtifact() {
506 return internalCreateOutputArtifact(getTarget());
507 }
508
509 /**
510 * Returns the output artifact of an {@link OutputFile} of this target.
511 *
512 * @see #createOutputArtifact()
513 */
514 public Artifact createOutputArtifact(OutputFile out) {
515 return internalCreateOutputArtifact(out);
516 }
517
518 /**
519 * Implementation for {@link #createOutputArtifact()} and
520 * {@link #createOutputArtifact(OutputFile)}. This is private so that
521 * {@link #createOutputArtifact(OutputFile)} can have a more specific
522 * signature.
523 */
524 private Artifact internalCreateOutputArtifact(Target target) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000525 Preconditions.checkState(
526 target.getLabel().getPackageIdentifier().equals(getLabel().getPackageIdentifier()),
527 "Creating output artifact for target '%s' in different package than the rule '%s' "
528 + "being analyzed", target.getLabel(), getLabel());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100529 Root root = getBinOrGenfilesDirectory();
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000530 return getPackageRelativeArtifact(target.getName(), root);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100531 }
532
533 /**
534 * Returns the root of either the "bin" or "genfiles"
535 * tree, based on this target and the current configuration.
536 * The choice of which tree to use is based on the rule with
537 * which this target (which must be an OutputFile or a Rule) is associated.
538 */
539 public Root getBinOrGenfilesDirectory() {
Kristina Chodorowba41c2d2016-10-10 17:21:24 +0000540 return rule.hasBinaryOutput()
541 ? getConfiguration().getBinDirectory(rule.getRepository())
542 : getConfiguration().getGenfilesDirectory(rule.getRepository());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100543 }
544
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000545 /**
546 * Creates an artifact in a directory that is unique to the package that contains the rule,
547 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
548 */
549 public Artifact getPackageRelativeArtifact(String relative, Root root) {
nharmatab4060b62017-04-04 17:11:39 +0000550 return getPackageRelativeArtifact(PathFragment.create(relative), root);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000551 }
552
553 /**
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000554 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
555 * guaranteeing that it never clashes with artifacts created by rules in other packages.
556 */
557 public Artifact getBinArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000558 return getBinArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000559 }
560
561 public Artifact getBinArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000562 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000563 relative, getConfiguration().getBinDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000564 }
565
566 /**
567 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
568 * guaranteeing that it never clashes with artifacts created by rules in other packages.
569 */
570 public Artifact getGenfilesArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000571 return getGenfilesArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000572 }
573
574 public Artifact getGenfilesArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000575 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000576 relative, getConfiguration().getGenfilesDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000577 }
578
579 /**
Lukacs Berki21a04f22015-08-20 13:31:24 +0000580 * Returns an artifact that can be an output of shared actions. Only use when there is no other
581 * option.
582 *
583 * <p>This artifact can be created anywhere in the output tree, which, in addition to making
584 * sharing possible, opens up the possibility of action conflicts and makes it impossible to
585 * infer the label of the rule creating the artifact from the path of the artifact.
586 */
587 public Artifact getShareableArtifact(PathFragment rootRelativePath, Root root) {
588 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root);
589 }
590
591 /**
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000592 * Creates an artifact in a directory that is unique to the package that contains the rule,
593 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
594 */
595 public Artifact getPackageRelativeArtifact(PathFragment relative, Root root) {
596 return getDerivedArtifact(getPackageDirectory().getRelative(relative), root);
597 }
598
599 /**
600 * Returns the root-relative path fragment under which output artifacts of this rule should go.
601 *
602 * <p>Note that:
603 * <ul>
604 * <li>This doesn't guarantee that there are no clashes with rules in the same package.
605 * <li>If possible, {@link #getPackageRelativeArtifact(PathFragment, Root)} should be used
606 * instead of this method.
607 * </ul>
608 *
609 * Ideally, user-visible artifacts should all have corresponding output file targets, all others
610 * should go into a rule-specific directory.
611 * {@link #getUniqueDirectoryArtifact(String, PathFragment, Root)}) ensures that this is the case.
612 */
613 public PathFragment getPackageDirectory() {
Dmitry Lomove36a66c2017-02-17 14:48:48 +0000614 return getLabel().getPackageIdentifier().getSourceRoot();
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000615 }
616
617 /**
618 * Creates an artifact under a given root with the given root-relative path.
619 *
620 * <p>Verifies that it is in the root-relative directory corresponding to the package of the rule,
621 * thus ensuring that it doesn't clash with other artifacts generated by other rules using this
622 * method.
623 */
Ulf Adams3ab82f72015-09-04 12:10:53 +0000624 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000625 public Artifact getDerivedArtifact(PathFragment rootRelativePath, Root root) {
626 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
627 "Output artifact '%s' not under package directory '%s' for target '%s'",
628 rootRelativePath, getPackageDirectory(), getLabel());
629 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root);
630 }
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000631
632 /**
633 * Creates a TreeArtifact under a given root with the given root-relative path.
634 *
635 * <p>Verifies that it is in the root-relative directory corresponding to the package of the rule,
636 * thus ensuring that it doesn't clash with other artifacts generated by other rules using this
637 * method.
638 */
639 public Artifact getTreeArtifact(PathFragment rootRelativePath, Root root) {
640 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
641 "Output artifact '%s' not under package directory '%s' for target '%s'",
642 rootRelativePath, getPackageDirectory(), getLabel());
643 return getAnalysisEnvironment().getTreeArtifact(rootRelativePath, root);
644 }
645
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000646 /**
allevato060a4482017-03-30 20:45:52 +0000647 * Creates a tree artifact in a directory that is unique to the package that contains the rule,
648 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
649 */
650 public Artifact getPackageRelativeTreeArtifact(PathFragment relative, Root root) {
651 return getTreeArtifact(getPackageDirectory().getRelative(relative), root);
652 }
653
654 /**
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000655 * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
656 * clashes with artifacts created by other rules.
657 */
658 public Artifact getUniqueDirectoryArtifact(
659 String uniqueDirectory, String relative, Root root) {
nharmatab4060b62017-04-04 17:11:39 +0000660 return getUniqueDirectoryArtifact(uniqueDirectory, PathFragment.create(relative), root);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000661 }
662
Lukacs Berkid6e64242015-07-30 17:06:23 +0000663 /**
664 * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
665 * clashes with artifacts created by other rules.
666 */
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000667 public Artifact getUniqueDirectoryArtifact(
668 String uniqueDirectory, PathFragment relative, Root root) {
669 return getDerivedArtifact(getUniqueDirectory(uniqueDirectory).getRelative(relative), root);
670 }
671
Googler03083852015-12-06 18:31:53 +0000672 /**
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000673 * Returns true iff the rule, or any attached aspect, has an attribute with the given name and
674 * type.
675 */
676 public boolean isAttrDefined(String attrName, Type<?> type) {
Greg Estren7f534232016-12-01 21:38:25 +0000677 return attributes().has(attrName, type);
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000678 }
679
680 /**
Lukacs Berki8bdae762016-07-13 14:58:54 +0000681 * Returns the dependencies through a {@code LABEL_DICT_UNARY} attribute as a map from
682 * a string to a {@link TransitiveInfoCollection}.
683 */
684 public Map<String, TransitiveInfoCollection> getPrerequisiteMap(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +0000685 Preconditions.checkState(attributes().has(attributeName, BuildType.LABEL_DICT_UNARY));
Lukacs Berki8bdae762016-07-13 14:58:54 +0000686
687 ImmutableMap.Builder<String, TransitiveInfoCollection> result = ImmutableMap.builder();
688 Map<String, Label> dict = attributes().get(attributeName, BuildType.LABEL_DICT_UNARY);
689 Map<Label, ConfiguredTarget> labelToDep = new HashMap<>();
690 for (ConfiguredTarget dep : targetMap.get(attributeName)) {
691 labelToDep.put(dep.getLabel(), dep);
692 }
693
694 for (Map.Entry<String, Label> entry : dict.entrySet()) {
695 result.put(entry.getKey(), Preconditions.checkNotNull(labelToDep.get(entry.getValue())));
696 }
697
698 return result.build();
699 }
700
701 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100702 * Returns the list of transitive info collections that feed into this target through the
703 * specified attribute. Note that you need to specify the correct mode for the attribute,
704 * otherwise an assertion will be raised.
705 */
706 public List<? extends TransitiveInfoCollection> getPrerequisites(String attributeName,
707 Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +0000708 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000709 if ((mode == Mode.TARGET) && (attributeDefinition.hasSplitConfigurationTransition())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100710 // TODO(bazel-team): If you request a split-configured attribute in the target configuration,
711 // we return only the list of configured targets for the first architecture; this is for
712 // backwards compatibility with existing code in cases where the call to getPrerequisites is
713 // deeply nested and we can't easily inject the behavior we want. However, we should fix all
714 // such call sites.
715 checkAttribute(attributeName, Mode.SPLIT);
Googler59480b92016-07-22 17:06:40 +0000716 Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> map =
717 getSplitPrerequisites(attributeName);
dslomovde965ac2017-07-31 21:07:51 +0200718 return map.isEmpty() ? ImmutableList.of() : map.entrySet().iterator().next().getValue();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100719 }
720
721 checkAttribute(attributeName, mode);
722 return targetMap.get(attributeName);
723 }
724
725 /**
Googler59480b92016-07-22 17:06:40 +0000726 * Returns the a prerequisites keyed by the CPU of their configurations.
727 * If the split transition is not active (e.g. split() returned an empty
728 * list), the key is an empty Optional.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100729 */
Googler59480b92016-07-22 17:06:40 +0000730 public Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>>
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100731 getSplitPrerequisites(String attributeName) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100732 checkAttribute(attributeName, Mode.SPLIT);
733
Greg Estren7f534232016-12-01 21:38:25 +0000734 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
Greg Estren66cadd32016-08-05 21:07:02 +0000735 @SuppressWarnings("unchecked") // Attribute.java doesn't have the BuildOptions symbol.
736 SplitTransition<BuildOptions> transition =
737 (SplitTransition<BuildOptions>) attributeDefinition.getSplitTransition(rule);
738 List<ConfiguredTarget> deps = targetMap.get(attributeName);
739
740 List<BuildOptions> splitOptions = transition.split(getConfiguration().getOptions());
741 if (splitOptions.isEmpty()) {
Googler59480b92016-07-22 17:06:40 +0000742 // The split transition is not active. Defer the decision on which CPU to use.
Greg Estren66cadd32016-08-05 21:07:02 +0000743 return ImmutableMap.of(Optional.<String>absent(), deps);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100744 }
745
746 Set<String> cpus = new HashSet<>();
Greg Estren66cadd32016-08-05 21:07:02 +0000747 for (BuildOptions options : splitOptions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100748 // This method should only be called when the split config is enabled on the command line, in
749 // which case this cpu can't be null.
Ulf Adams111006e2016-09-12 15:57:06 +0000750 cpus.add(options.get(BuildConfiguration.Options.class).cpu);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100751 }
752
753 // Use an ImmutableListMultimap.Builder here to preserve ordering.
Googler59480b92016-07-22 17:06:40 +0000754 ImmutableListMultimap.Builder<Optional<String>, TransitiveInfoCollection> result =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100755 ImmutableListMultimap.builder();
Greg Estren66cadd32016-08-05 21:07:02 +0000756 for (TransitiveInfoCollection t : deps) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100757 if (t.getConfiguration() != null) {
Googler59480b92016-07-22 17:06:40 +0000758 result.put(Optional.of(t.getConfiguration().getCpu()), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100759 } else {
760 // Source files don't have a configuration, so we add them to all architecture entries.
761 for (String cpu : cpus) {
Googler59480b92016-07-22 17:06:40 +0000762 result.put(Optional.of(cpu), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100763 }
764 }
765 }
766 return Multimaps.asMap(result.build());
767 }
768
769 /**
770 * Returns the specified provider of the prerequisite referenced by the attribute in the
771 * argument. Note that you need to specify the correct mode for the attribute, otherwise an
gregce47d57852017-06-26 23:01:54 +0200772 * assertion will be raised. If the attribute is empty or it does not support the specified
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100773 * provider, returns null.
774 */
775 public <C extends TransitiveInfoProvider> C getPrerequisite(
776 String attributeName, Mode mode, Class<C> provider) {
777 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
778 return prerequisite == null ? null : prerequisite.getProvider(provider);
779 }
780
781 /**
782 * Returns the transitive info collection that feeds into this target through the specified
783 * attribute. Note that you need to specify the correct mode for the attribute, otherwise an
784 * assertion will be raised. Returns null if the attribute is empty.
785 */
786 public TransitiveInfoCollection getPrerequisite(String attributeName, Mode mode) {
787 checkAttribute(attributeName, mode);
788 List<? extends TransitiveInfoCollection> elements = targetMap.get(attributeName);
789 if (elements.size() > 1) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000790 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
791 + " produces more than one prerequisite");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100792 }
793 return elements.isEmpty() ? null : elements.get(0);
794 }
795
796 /**
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000797 * For a given attribute, returns all {@link TransitiveInfoProvider}s provided by targets
798 * of that attribute. Each {@link TransitiveInfoProvider} is keyed by the
799 * {@link BuildConfiguration} under which the provider was created.
800 */
801 public <C extends TransitiveInfoProvider> ImmutableListMultimap<BuildConfiguration, C>
802 getPrerequisitesByConfiguration(String attributeName, Mode mode, final Class<C> classType) {
803 AnalysisUtils.checkProvider(classType);
804 List<? extends TransitiveInfoCollection> transitiveInfoCollections =
805 getPrerequisites(attributeName, mode);
Chris Parsons0d7f0412016-04-29 20:35:44 +0000806
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000807 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
808 ImmutableListMultimap.builder();
809 for (TransitiveInfoCollection prerequisite : transitiveInfoCollections) {
810 C prerequisiteProvider = prerequisite.getProvider(classType);
811 if (prerequisiteProvider != null) {
812 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
813 }
814 }
815 return result.build();
816 }
817
818 /**
dslomovde965ac2017-07-31 21:07:51 +0200819 * For a given attribute, returns all declared provider provided by targets of that attribute.
820 * Each declared provider is keyed by the {@link BuildConfiguration} under which the provider was
821 * created.
dslomov4e9fa192017-07-12 14:59:07 +0200822 */
dslomovde965ac2017-07-31 21:07:51 +0200823 public <C extends Info>
824 ImmutableListMultimap<BuildConfiguration, C> getPrerequisitesByConfiguration(
825 String attributeName, Mode mode, final NativeProvider<C> provider) {
dslomov4e9fa192017-07-12 14:59:07 +0200826 List<? extends TransitiveInfoCollection> transitiveInfoCollections =
827 getPrerequisites(attributeName, mode);
828
829 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
830 ImmutableListMultimap.builder();
831 for (TransitiveInfoCollection prerequisite : transitiveInfoCollections) {
832 C prerequisiteProvider = prerequisite.get(provider);
833 if (prerequisiteProvider != null) {
834 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
835 }
836 }
837 return result.build();
838 }
839
840 /**
Chris Parsons0d7f0412016-04-29 20:35:44 +0000841 * For a given attribute, returns all {@link TransitiveInfoCollection}s provided by targets
842 * of that attribute. Each {@link TransitiveInfoCollection} is keyed by the
843 * {@link BuildConfiguration} under which the collection was created.
844 */
845 public ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection>
846 getPrerequisitesByConfiguration(String attributeName, Mode mode) {
847 List<? extends TransitiveInfoCollection> transitiveInfoCollections =
848 getPrerequisites(attributeName, mode);
849
850 ImmutableListMultimap.Builder<BuildConfiguration, TransitiveInfoCollection> result =
851 ImmutableListMultimap.builder();
852 for (TransitiveInfoCollection prerequisite : transitiveInfoCollections) {
853 result.put(prerequisite.getConfiguration(), prerequisite);
854 }
855 return result.build();
856 }
857
858 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100859 * Returns all the providers of the specified type that are listed under the specified attribute
860 * of this target in the BUILD file.
861 */
862 public <C extends TransitiveInfoProvider> Iterable<C> getPrerequisites(String attributeName,
863 Mode mode, final Class<C> classType) {
864 AnalysisUtils.checkProvider(classType);
865 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), classType);
866 }
867
868 /**
Sergio Campamafd931432016-12-09 21:47:35 +0000869 * Returns all the declared providers (native and Skylark) for the specified constructor under the
870 * specified attribute of this target in the BUILD file.
871 */
dslomovde965ac2017-07-31 21:07:51 +0200872 public <T extends Info> Iterable<T> getPrerequisites(
873 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
dslomov77baa4c2017-07-10 17:15:27 +0200874 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), skylarkKey);
Sergio Campamafd931432016-12-09 21:47:35 +0000875 }
876
877 /**
Sergio Campamae8cecd92016-12-13 18:49:28 +0000878 * Returns the declared provider (native and Skylark) for the specified constructor under the
879 * specified attribute of this target in the BUILD file. May return null if there is no
880 * TransitiveInfoCollection under the specified attribute.
881 */
882 @Nullable
dslomovde965ac2017-07-31 21:07:51 +0200883 public <T extends Info> T getPrerequisite(
884 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
Sergio Campamae8cecd92016-12-13 18:49:28 +0000885 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
886 return prerequisite == null ? null : prerequisite.get(skylarkKey);
887 }
888
889 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100890 * Returns all the providers of the specified type that are listed under the specified attribute
891 * of this target in the BUILD file, and that contain the specified provider.
892 */
893 public <C extends TransitiveInfoProvider> Iterable<? extends TransitiveInfoCollection>
894 getPrerequisitesIf(String attributeName, Mode mode, final Class<C> classType) {
895 AnalysisUtils.checkProvider(classType);
896 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
897 }
898
899 /**
dslomov73527c32017-07-27 17:35:46 +0200900 * Returns all the providers of the specified type that are listed under the specified attribute
901 * of this target in the BUILD file, and that contain the specified provider.
902 */
dslomovde965ac2017-07-31 21:07:51 +0200903 public <C extends Info> Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
904 String attributeName, Mode mode, final NativeProvider<C> classType) {
dslomov73527c32017-07-27 17:35:46 +0200905 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
906 }
907
908
909 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100910 * Returns the prerequisite referred to by the specified attribute. Also checks whether
911 * the attribute is marked as executable and that the target referred to can actually be
912 * executed.
913 *
914 * <p>The {@code mode} argument must match the configuration transition specified in the
915 * definition of the attribute.
916 *
917 * @param attributeName the name of the attribute
918 * @param mode the configuration transition of the attribute
919 *
920 * @return the {@link FilesToRunProvider} interface of the prerequisite.
921 */
Carmi Grushko802f39e2016-04-06 20:03:56 +0000922 @Nullable
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100923 public FilesToRunProvider getExecutablePrerequisite(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +0000924 Attribute ruleDefinition = attributes().getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100925
926 if (ruleDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000927 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100928 + " is not defined");
929 }
930 if (!ruleDefinition.isExecutable()) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000931 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100932 + " is not configured to be executable");
933 }
934
935 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
936 if (prerequisite == null) {
937 return null;
938 }
939
940 FilesToRunProvider result = prerequisite.getProvider(FilesToRunProvider.class);
941 if (result == null || result.getExecutable() == null) {
942 attributeError(
943 attributeName, prerequisite.getLabel() + " does not refer to a valid executable target");
944 }
945 return result;
946 }
947
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +0000948 /** Indicates whether a string list attribute should be tokenized. */
949 public enum Tokenize {
950 YES,
951 NO
952 }
953
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100954 /**
Ulf Adamse685ef32015-07-29 15:28:01 +0000955 * Gets an attribute of type STRING_LIST expanding Make variables, $(location) tags into the
956 * dependency location (see {@link LocationExpander} for details) and tokenizes the result.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100957 *
958 * @param attributeName the name of the attribute to process
Damien Martin-Guillerezbb46c872015-03-06 12:04:35 +0000959 * @return a list of strings containing the expanded and tokenized values for the attribute
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100960 */
Ulf Adams10993fe2016-04-19 12:55:12 +0000961 public ImmutableList<String> getTokenizedStringListAttr(String attributeName) {
hlopkoa4778052017-05-26 11:37:28 +0200962 return getExpandedStringListAttr(attributeName, Tokenize.YES, Collections.EMPTY_LIST);
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +0000963 }
964
965 /**
hlopkoa4778052017-05-26 11:37:28 +0200966 * Gets an attribute of type STRING_LIST expanding Make variables, $(location) tags into the
967 * dependency location (see {@link LocationExpander} for details) and tokenizes the result.
968 *
969 * @param attributeName the name of the attribute to process
970 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
971 * @return a list of strings containing the expanded and tokenized values for the attribute
972 */
973 public ImmutableList<String> getTokenizedStringListAttr(
974 String attributeName, Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
975 return getExpandedStringListAttr(attributeName, Tokenize.YES, makeVariableSuppliers);
976 }
977
978 /**
979 * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags, and
980 * optionally tokenizes the result. Doesn't register any {@link MakeVariableSupplier}.
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +0000981 *
982 * @param attributeName the name of the attribute to process
983 * @return a list of strings containing the processed values for the attribute
984 */
Ulf Adams10993fe2016-04-19 12:55:12 +0000985 public ImmutableList<String> getExpandedStringListAttr(String attributeName, Tokenize tokenize) {
hlopkoa4778052017-05-26 11:37:28 +0200986 return getExpandedStringListAttr(
987 attributeName, tokenize, ImmutableList.<MakeVariableSupplier>of());
988 }
989
990 /**
991 * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags, and
992 * optionally tokenizes the result.
993 *
994 * @param attributeName the name of the attribute to process
995 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
996 * @return a list of strings containing the processed values for the attribute
997 */
998 public ImmutableList<String> getExpandedStringListAttr(
999 String attributeName,
1000 Tokenize tokenize,
1001 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001002 if (!getRule().isAttrDefined(attributeName, Type.STRING_LIST)) {
1003 // TODO(bazel-team): This should be an error.
1004 return ImmutableList.of();
1005 }
1006 List<String> original = attributes().get(attributeName, Type.STRING_LIST);
1007 if (original.isEmpty()) {
1008 return ImmutableList.of();
1009 }
1010 List<String> tokens = new ArrayList<>();
Damien Martin-Guillerezbb46c872015-03-06 12:04:35 +00001011 LocationExpander locationExpander =
Ulf Adamse685ef32015-07-29 15:28:01 +00001012 new LocationExpander(this, LocationExpander.Options.ALLOW_DATA);
Damien Martin-Guillerezbb46c872015-03-06 12:04:35 +00001013
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001014 for (String token : original) {
hlopkoa4778052017-05-26 11:37:28 +02001015 expandValue(tokens, attributeName, token, locationExpander, tokenize, makeVariableSuppliers);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001016 }
1017 return ImmutableList.copyOf(tokens);
1018 }
1019
1020 /**
1021 * Expands make variables in value and tokenizes the result into tokens.
1022 *
hlopkoa4778052017-05-26 11:37:28 +02001023 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
1024 * <p>This methods should be called only during initialization.
Damien Martin-Guillerezbb46c872015-03-06 12:04:35 +00001025 */
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001026 public void tokenizeAndExpandMakeVars(
1027 List<String> tokens,
1028 String attributeName,
1029 String value,
hlopkoa4778052017-05-26 11:37:28 +02001030 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
1031 LocationExpander locationExpander =
1032 new LocationExpander(this, Options.ALLOW_DATA, Options.EXEC_PATHS);
1033 tokenizeAndExpandMakeVars(
1034 tokens, attributeName, value, locationExpander, makeVariableSuppliers);
1035 }
1036
1037 /**
1038 * Expands make variables and $(location) tags in value and tokenizes the result into tokens.
1039 *
1040 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
1041 * <p>This methods should be called only during initialization.
1042 */
1043 public void tokenizeAndExpandMakeVars(
1044 List<String> tokens,
1045 String attributeName,
1046 String value,
1047 @Nullable LocationExpander locationExpander,
1048 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
1049 expandValue(
1050 tokens, attributeName, value, locationExpander, Tokenize.YES, makeVariableSuppliers);
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001051 }
1052
1053 /**
1054 * Expands make variables and $(location) tags in value, and optionally tokenizes the result.
1055 *
hlopkoa4778052017-05-26 11:37:28 +02001056 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
1057 * <p>This methods should be called only during initialization.
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001058 */
1059 public void expandValue(
1060 List<String> tokens,
1061 String attributeName,
1062 String value,
1063 @Nullable LocationExpander locationExpander,
hlopkoa4778052017-05-26 11:37:28 +02001064 Tokenize tokenize,
1065 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001066 if (locationExpander != null) {
1067 value = locationExpander.expandAttribute(attributeName, value);
1068 }
hlopkoa4778052017-05-26 11:37:28 +02001069 value = expandMakeVariables(attributeName, value, makeVariableSuppliers);
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001070 if (tokenize == Tokenize.YES) {
1071 try {
1072 ShellUtils.tokenize(tokens, value);
1073 } catch (ShellUtils.TokenizationException e) {
1074 attributeError(attributeName, e.getMessage());
Damien Martin-Guillerezbb46c872015-03-06 12:04:35 +00001075 }
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001076 } else {
1077 tokens.add(value);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001078 }
1079 }
1080
lberki6cd3b2d2017-05-05 09:18:48 +02001081 public ImmutableMap<String, String> getMakeVariables(Iterable<String> attributeNames) {
lberki3c1c8e92017-07-13 12:25:47 +02001082 ArrayList<MakeVariableProvider> makeVariableProviders = new ArrayList<>();
lberki6cd3b2d2017-05-05 09:18:48 +02001083
1084 for (String attributeName : attributeNames) {
1085 // TODO(b/37567440): Remove this continue statement.
1086 if (!attributes().has(attributeName)) {
1087 continue;
1088 }
lberki3c1c8e92017-07-13 12:25:47 +02001089 Iterables.addAll(makeVariableProviders,
dslomov2d05de22017-07-11 16:45:02 +02001090 getPrerequisites(attributeName, Mode.TARGET, MakeVariableProvider.SKYLARK_CONSTRUCTOR));
lberki6cd3b2d2017-05-05 09:18:48 +02001091 }
1092
lberki3c1c8e92017-07-13 12:25:47 +02001093 LinkedHashMap<String, String> makeVariables = new LinkedHashMap<>();
1094 for (MakeVariableProvider makeVariableProvider : makeVariableProviders) {
1095 makeVariables.putAll(makeVariableProvider.getMakeVariables());
lberki6cd3b2d2017-05-05 09:18:48 +02001096 }
1097
lberki3c1c8e92017-07-13 12:25:47 +02001098 return ImmutableMap.copyOf(makeVariables);
lberki6cd3b2d2017-05-05 09:18:48 +02001099 }
1100
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001101 /**
hlopkoa4778052017-05-26 11:37:28 +02001102 * Returns a (cached! read on) context that maps Make variable names (string) to values (string)
1103 * without any extra {@link MakeVariableSupplier}.
1104 *
1105 * <p>Beware!!! {@link ConfigurationMakeVariableContext} instance is cached, so if you call it
1106 * first with some list of {@link MakeVariableSupplier} and then with other list, you will always
1107 * get the first instance back. TODO(hlopko): Extract Make variable expansion from RuleContext and
1108 * fix all the callers
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001109 *
1110 * @return a ConfigurationMakeVariableContext.
hlopkoa4778052017-05-26 11:37:28 +02001111 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001112 public ConfigurationMakeVariableContext getConfigurationMakeVariableContext() {
hlopkoa4778052017-05-26 11:37:28 +02001113 return getConfigurationMakeVariableContext(ImmutableList.<MakeVariableSupplier>of());
1114 }
1115
1116 /**
1117 * Returns a (cached! read on) context that maps Make variable names (string) to values (string).
1118 *
1119 * @see #getConfigurationMakeVariableContext() to understand how the instance is cached!
1120 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
1121 * @return a ConfigurationMakeVariableContext.
1122 */
1123 public ConfigurationMakeVariableContext getConfigurationMakeVariableContext(
1124 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001125 if (configurationMakeVariableContext == null) {
lberki6cd3b2d2017-05-05 09:18:48 +02001126 configurationMakeVariableContext =
hlopkoa4778052017-05-26 11:37:28 +02001127 new ConfigurationMakeVariableContext(
1128 this, getRule().getPackage(), getConfiguration(), makeVariableSuppliers);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001129 }
1130 return configurationMakeVariableContext;
1131 }
1132
1133 /**
lberkid579b6e2017-07-10 14:28:56 +02001134 * Expands the make variables in {@code expression}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001135 *
lberkid579b6e2017-07-10 14:28:56 +02001136 * @param attributeName the name of the attribute from which "expression" comes; used for error
1137 * reporting.
1138 * @param expression the string to expand.
1139 * @return the expanded string.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001140 */
1141 public String expandMakeVariables(String attributeName, String expression) {
hlopkoa4778052017-05-26 11:37:28 +02001142 return expandMakeVariables(attributeName, expression, ImmutableList.<MakeVariableSupplier>of());
1143 }
1144
1145 /**
1146 * Returns the string "expression" after expanding all embedded references to "Make" variables. If
1147 * any errors are encountered, they are reported, and "expression" is returned unchanged.
1148 *
1149 * @param attributeName the name of the attribute from which "expression" comes; used for error
1150 * reporting.
1151 * @param expression the string to expand.
1152 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
1153 * @return the expansion of "expression".
1154 */
1155 public String expandMakeVariables(
1156 String attributeName,
1157 String expression,
1158 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
1159 return expandMakeVariables(
1160 attributeName, expression, getConfigurationMakeVariableContext(makeVariableSuppliers));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001161 }
1162
1163 /**
1164 * Returns the string "expression" after expanding all embedded references to
1165 * "Make" variables. If any errors are encountered, they are reported, and
1166 * "expression" is returned unchanged.
1167 *
1168 * @param attributeName the name of the attribute from which "expression" comes;
1169 * used for error reporting.
1170 * @param expression the string to expand.
1171 * @param context the ConfigurationMakeVariableContext which can have a customized
1172 * lookupMakeVariable(String) method.
1173 * @return the expansion of "expression".
1174 */
1175 public String expandMakeVariables(String attributeName, String expression,
1176 ConfigurationMakeVariableContext context) {
1177 try {
1178 return MakeVariableExpander.expand(expression, context);
1179 } catch (MakeVariableExpander.ExpansionException e) {
1180 attributeError(attributeName, e.getMessage());
1181 return expression;
1182 }
1183 }
1184
1185 /**
1186 * Gets the value of the STRING_LIST attribute expanding all make variables.
1187 */
1188 public List<String> expandedMakeVariablesList(String attrName) {
1189 List<String> variables = new ArrayList<>();
1190 for (String variable : attributes().get(attrName, Type.STRING_LIST)) {
hlopkoa4778052017-05-26 11:37:28 +02001191 variables.add(
1192 expandMakeVariables(attrName, variable, ImmutableList.<MakeVariableSupplier>of()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001193 }
1194 return variables;
1195 }
1196
1197 /**
hlopkoa4778052017-05-26 11:37:28 +02001198 * If the string consists of a single variable, returns the expansion of that variable. Otherwise,
1199 * returns null. Syntax errors are reported.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001200 *
hlopkoa4778052017-05-26 11:37:28 +02001201 * @param attrName the name of the attribute from which "expression" comes; used for error
1202 * reporting.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001203 * @param expression the string to expand.
hlopkoa4778052017-05-26 11:37:28 +02001204 * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001205 * @return the expansion of "expression", or null.
1206 */
hlopkoa4778052017-05-26 11:37:28 +02001207 public String expandSingleMakeVariable(
1208 String attrName,
1209 String expression,
1210 ImmutableList<? extends MakeVariableSupplier> makeVariableSuppliers) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001211 try {
lberki6cd3b2d2017-05-05 09:18:48 +02001212 return MakeVariableExpander.expandSingleVariable(
hlopkoa4778052017-05-26 11:37:28 +02001213 expression, getConfigurationMakeVariableContext(makeVariableSuppliers));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001214 } catch (MakeVariableExpander.ExpansionException e) {
1215 attributeError(attrName, e.getMessage());
1216 return expression;
1217 }
1218 }
1219
John Cater13263f72017-05-24 19:06:47 +02001220 @Nullable
John Catereca28402017-05-17 21:44:12 +02001221 public ToolchainContext getToolchainContext() {
1222 return toolchainContext;
1223 }
1224
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001225 private void checkAttribute(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +00001226 Attribute attributeDefinition = attributes.getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001227 if (attributeDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001228 throw new IllegalStateException(getRule().getLocation() + ": " + getRuleClassNameForLogging()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001229 + " attribute " + attributeName + " is not defined");
1230 }
Michael Staiba751f922017-02-14 15:50:04 +00001231 if (attributeDefinition.getType().getLabelClass() != LabelClass.DEPENDENCY) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001232 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001233 + " is not a label type attribute");
1234 }
1235 if (mode == Mode.HOST) {
1236 if (attributeDefinition.getConfigurationTransition() != ConfigurationTransition.HOST) {
1237 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001238 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001239 + " is not configured for the host configuration");
1240 }
1241 } else if (mode == Mode.TARGET) {
1242 if (attributeDefinition.getConfigurationTransition() != ConfigurationTransition.NONE) {
1243 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001244 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001245 + " is not configured for the target configuration");
1246 }
1247 } else if (mode == Mode.DATA) {
1248 if (attributeDefinition.getConfigurationTransition() != ConfigurationTransition.DATA) {
1249 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001250 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001251 + " is not configured for the data configuration");
1252 }
1253 } else if (mode == Mode.SPLIT) {
Chris Parsons2e62c0d2016-04-19 22:13:59 +00001254 if (!(attributeDefinition.hasSplitConfigurationTransition())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001255 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001256 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001257 + " is not configured for a split transition");
1258 }
1259 }
1260 }
1261
1262 /**
1263 * Returns the Mode for which the attribute is configured.
1264 * This is intended for Skylark, where the Mode is implicitly chosen.
1265 */
1266 public Mode getAttributeMode(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +00001267 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001268 if (attributeDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001269 throw new IllegalStateException(getRule().getLocation() + ": " + getRuleClassNameForLogging()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001270 + " attribute " + attributeName + " is not defined");
1271 }
Michael Staiba751f922017-02-14 15:50:04 +00001272 if (attributeDefinition.getType().getLabelClass() != LabelClass.DEPENDENCY) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001273 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001274 + " is not a label type attribute");
1275 }
1276 if (attributeDefinition.getConfigurationTransition() == ConfigurationTransition.HOST) {
1277 return Mode.HOST;
1278 } else if (attributeDefinition.getConfigurationTransition() == ConfigurationTransition.NONE) {
1279 return Mode.TARGET;
1280 } else if (attributeDefinition.getConfigurationTransition() == ConfigurationTransition.DATA) {
1281 return Mode.DATA;
Chris Parsons2e62c0d2016-04-19 22:13:59 +00001282 } else if (attributeDefinition.hasSplitConfigurationTransition()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001283 return Mode.SPLIT;
1284 }
1285 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001286 + getRuleClassNameForLogging() + " attribute " + attributeName + " is not configured");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001287 }
1288
1289 /**
1290 * For the specified attribute "attributeName" (which must be of type
1291 * list(label)), resolve all the labels into ConfiguredTargets (for the
1292 * configuration appropriate to the attribute) and return their build
1293 * artifacts as a {@link PrerequisiteArtifacts} instance.
1294 *
1295 * @param attributeName the name of the attribute to traverse
1296 */
1297 public PrerequisiteArtifacts getPrerequisiteArtifacts(String attributeName, Mode mode) {
1298 return PrerequisiteArtifacts.get(this, attributeName, mode);
1299 }
1300
1301 /**
1302 * For the specified attribute "attributeName" (which must be of type label),
1303 * resolves the ConfiguredTarget and returns its single build artifact.
1304 *
1305 * <p>If the attribute is optional, has no default and was not specified, then
1306 * null will be returned. Note also that null is returned (and an attribute
1307 * error is raised) if there wasn't exactly one build artifact for the target.
1308 */
1309 public Artifact getPrerequisiteArtifact(String attributeName, Mode mode) {
1310 TransitiveInfoCollection target = getPrerequisite(attributeName, mode);
1311 return transitiveInfoCollectionToArtifact(attributeName, target);
1312 }
1313
1314 /**
1315 * Equivalent to getPrerequisiteArtifact(), but also asserts that
1316 * host-configuration is appropriate for the specified attribute.
1317 */
1318 public Artifact getHostPrerequisiteArtifact(String attributeName) {
1319 TransitiveInfoCollection target = getPrerequisite(attributeName, Mode.HOST);
1320 return transitiveInfoCollectionToArtifact(attributeName, target);
1321 }
1322
1323 private Artifact transitiveInfoCollectionToArtifact(
1324 String attributeName, TransitiveInfoCollection target) {
1325 if (target != null) {
1326 Iterable<Artifact> artifacts = target.getProvider(FileProvider.class).getFilesToBuild();
1327 if (Iterables.size(artifacts) == 1) {
1328 return Iterables.getOnlyElement(artifacts);
1329 } else {
1330 attributeError(attributeName, target.getLabel() + " expected a single artifact");
1331 }
1332 }
1333 return null;
1334 }
1335
1336 /**
1337 * Returns the sole file in the "srcs" attribute. Reports an error and
1338 * (possibly) returns null if "srcs" does not identify a single file of the
1339 * expected type.
1340 */
1341 public Artifact getSingleSource(String fileTypeName) {
1342 List<Artifact> srcs = PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list();
1343 switch (srcs.size()) {
1344 case 0 : // error already issued by getSrc()
1345 return null;
1346 case 1 : // ok
1347 return Iterables.getOnlyElement(srcs);
1348 default :
1349 attributeError("srcs", "only a single " + fileTypeName + " is allowed here");
1350 return srcs.get(0);
1351 }
1352 }
1353
1354 public Artifact getSingleSource() {
Michael Staib8824d5e2016-01-20 21:37:05 +00001355 return getSingleSource(getRuleClassNameForLogging() + " source file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001356 }
1357
1358 /**
1359 * Returns a path fragment qualified by the rule name and unique fragment to
1360 * disambiguate artifacts produced from the source file appearing in
1361 * multiple rules.
1362 *
1363 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1364 */
1365 public final PathFragment getUniqueDirectory(String fragment) {
nharmata5e924af2017-05-02 18:16:23 +02001366 return getUniqueDirectory(PathFragment.create(fragment));
1367 }
1368
1369 /**
1370 * Returns a path fragment qualified by the rule name and unique fragment to
1371 * disambiguate artifacts produced from the source file appearing in
1372 * multiple rules.
1373 *
1374 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1375 */
1376 public final PathFragment getUniqueDirectory(PathFragment fragment) {
1377 return AnalysisUtils.getUniqueDirectory(getLabel(), fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001378 }
1379
1380 /**
1381 * Check that all targets that were specified as sources are from the same
1382 * package as this rule. Output a warning or an error for every target that is
1383 * imported from a different package.
1384 */
1385 public void checkSrcsSamePackage(boolean onlyWarn) {
1386 PathFragment packageName = getLabel().getPackageFragment();
1387 for (Artifact srcItem : PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list()) {
1388 if (!srcItem.isSourceArtifact()) {
1389 // In theory, we should not do this check. However, in practice, we
1390 // have a couple of rules that do not obey the "srcs must contain
1391 // files and only files" rule. Thus, we are stuck with this hack here :(
1392 continue;
1393 }
1394 Label associatedLabel = srcItem.getOwner();
1395 PathFragment itemPackageName = associatedLabel.getPackageFragment();
1396 if (!itemPackageName.equals(packageName)) {
1397 String message = "please do not import '" + associatedLabel + "' directly. "
1398 + "You should either move the file to this package or depend on "
1399 + "an appropriate rule there";
1400 if (onlyWarn) {
1401 attributeWarning("srcs", message);
1402 } else {
1403 attributeError("srcs", message);
1404 }
1405 }
1406 }
1407 }
1408
1409
1410 /**
1411 * Returns the label to which the {@code NODEP_LABEL} attribute
1412 * {@code attrName} refers, checking that it is a valid label, and that it is
1413 * referring to a local target. Reports a warning otherwise.
1414 */
1415 public Label getLocalNodepLabelAttribute(String attrName) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001416 Label label = attributes().get(attrName, BuildType.NODEP_LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001417 if (label == null) {
1418 return null;
1419 }
1420
1421 if (!getTarget().getLabel().getPackageFragment().equals(label.getPackageFragment())) {
1422 attributeWarning(attrName, "does not reference a local rule");
1423 }
1424
1425 return label;
1426 }
1427
1428 /**
1429 * Returns the implicit output artifact for a given template function. If multiple or no artifacts
1430 * can be found as a result of the template, an exception is thrown.
1431 */
Florian Weikert4b67d4f2015-09-14 13:35:34 +00001432 public Artifact getImplicitOutputArtifact(ImplicitOutputsFunction function)
1433 throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001434 Iterable<String> result;
1435 try {
1436 result = function.getImplicitOutputs(RawAttributeMapper.of(rule));
1437 } catch (EvalException e) {
1438 // It's ok as long as we don't use this method from Skylark.
1439 throw new IllegalStateException(e);
1440 }
1441 return getImplicitOutputArtifact(Iterables.getOnlyElement(result));
1442 }
1443
1444 /**
1445 * Only use from Skylark. Returns the implicit output artifact for a given output path.
1446 */
1447 public Artifact getImplicitOutputArtifact(String path) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +00001448 return getPackageRelativeArtifact(path, getBinOrGenfilesDirectory());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001449 }
1450
1451 /**
1452 * Convenience method to return a host configured target for the "compiler"
1453 * attribute. Allows caller to decide whether a warning should be printed if
1454 * the "compiler" attribute is not set to the default value.
1455 *
1456 * @param warnIfNotDefault if true, print a warning if the value for the
1457 * "compiler" attribute is set to something other than the default
1458 * @return a ConfiguredTarget using the host configuration for the "compiler"
1459 * attribute
1460 */
1461 public final FilesToRunProvider getCompiler(boolean warnIfNotDefault) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001462 Label label = attributes().get("compiler", BuildType.LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001463 if (warnIfNotDefault && !label.equals(getRule().getAttrDefaultValue("compiler"))) {
1464 attributeWarning("compiler", "setting the compiler is strongly discouraged");
1465 }
1466 return getExecutablePrerequisite("compiler", Mode.HOST);
1467 }
1468
1469 /**
1470 * Returns the (unmodifiable, ordered) list of artifacts which are the outputs
1471 * of this target.
1472 *
1473 * <p>Each element in this list is associated with a single output, either
1474 * declared implicitly (via setImplicitOutputsFunction()) or explicitly
1475 * (listed in the 'outs' attribute of our rule).
1476 */
1477 public final ImmutableList<Artifact> getOutputArtifacts() {
1478 ImmutableList.Builder<Artifact> artifacts = ImmutableList.builder();
1479 for (OutputFile out : getRule().getOutputFiles()) {
1480 artifacts.add(createOutputArtifact(out));
1481 }
1482 return artifacts.build();
1483 }
1484
1485 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001486 * Like {@link #getOutputArtifacts()} but for a singular output item.
1487 * Reports an error if the "out" attribute is not a singleton.
1488 *
1489 * @return null if the output list is empty, the artifact for the first item
1490 * of the output list otherwise
1491 */
1492 public Artifact getOutputArtifact() {
1493 List<Artifact> outs = getOutputArtifacts();
1494 if (outs.size() != 1) {
1495 attributeError("out", "exactly one output file required");
1496 if (outs.isEmpty()) {
1497 return null;
1498 }
1499 }
1500 return outs.get(0);
1501 }
1502
1503 /**
1504 * Returns an artifact with a given file extension. All other path components
1505 * are the same as in {@code pathFragment}.
1506 */
1507 public final Artifact getRelatedArtifact(PathFragment pathFragment, String extension) {
1508 PathFragment file = FileSystemUtils.replaceExtension(pathFragment, extension);
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +00001509 return getDerivedArtifact(file, getConfiguration().getBinDirectory(rule.getRepository()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001510 }
1511
1512 /**
Googlerf812a2f2016-06-13 16:14:10 +00001513 * Returns true if the target for this context is a test target.
1514 */
1515 public boolean isTestTarget() {
1516 return TargetUtils.isTestRule(getTarget());
1517 }
1518
1519 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001520 * Returns true if runfiles support should create the runfiles tree, or
1521 * false if it should just create the manifest.
1522 */
1523 public boolean shouldCreateRunfilesSymlinks() {
1524 // TODO(bazel-team): Ideally we wouldn't need such logic, and we'd
1525 // always use the BuildConfiguration#buildRunfiles() to determine
1526 // whether to build the runfiles. The problem is that certain build
1527 // steps actually consume their runfiles. These include:
1528 // a. par files consumes the runfiles directory
1529 // We should modify autopar to take a list of files instead.
1530 // of the runfiles directory.
1531 // b. host tools could potentially use data files, but currently don't
1532 // (they're run from the execution root, not a runfiles tree).
1533 // Currently hostConfiguration.buildRunfiles() returns true.
Googlerf812a2f2016-06-13 16:14:10 +00001534 if (isTestTarget()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001535 // Tests are only executed during testing (duh),
1536 // and their runfiles are generated lazily on local
1537 // execution (see LocalTestStrategy). Therefore, it
1538 // is safe not to build their runfiles.
1539 return getConfiguration().buildRunfiles();
1540 } else {
1541 return true;
1542 }
1543 }
1544
1545 /**
1546 * @return true if {@code rule} is visible from {@code prerequisite}.
1547 *
1548 * <p>This only computes the logic as implemented by the visibility system. The final decision
1549 * whether a dependency is allowed is made by
1550 * {@link ConfiguredRuleClassProvider.PrerequisiteValidator}.
1551 */
1552 public static boolean isVisible(Rule rule, TransitiveInfoCollection prerequisite) {
1553 // Check visibility attribute
1554 for (PackageSpecification specification :
1555 prerequisite.getProvider(VisibilityProvider.class).getVisibility()) {
Lukacs Berki485eb962016-01-13 10:47:29 +00001556 if (specification.containsPackage(rule.getLabel().getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001557 return true;
1558 }
1559 }
1560
1561 return false;
1562 }
1563
1564 /**
1565 * @return the set of features applicable for the current rule's package.
1566 */
1567 public ImmutableSet<String> getFeatures() {
1568 return features;
1569 }
1570
Florian Weikertb8a6a942015-09-25 12:36:08 +00001571 @Override
1572 public String toString() {
1573 return "RuleContext(" + getLabel() + ", " + getConfiguration() + ")";
1574 }
1575
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001576 /**
1577 * Builder class for a RuleContext.
1578 */
Florian Weikertb8a6a942015-09-25 12:36:08 +00001579 public static final class Builder implements RuleErrorConsumer {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001580 private final AnalysisEnvironment env;
1581 private final Rule rule;
Michael Staibb51251e2015-09-29 23:31:51 +00001582 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
Greg Estrenc5a352f2015-11-13 17:25:36 +00001583 private Class<? extends BuildConfiguration.Fragment> universalFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001584 private final BuildConfiguration configuration;
Greg Estren9eb1cf02015-06-26 22:18:35 +00001585 private final BuildConfiguration hostConfiguration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001586 private final PrerequisiteValidator prerequisiteValidator;
Florian Weikertb8a6a942015-09-25 12:36:08 +00001587 private final ErrorReporter reporter;
Greg Estrend5353252016-08-11 22:13:31 +00001588 private OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap;
Lukacs Berki7894c182016-05-10 12:07:01 +00001589 private ImmutableMap<Label, ConfigMatchingProvider> configConditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001590 private NestedSet<PackageSpecification> visibility;
Dmitry Lomovace678e2015-12-16 15:10:20 +00001591 private ImmutableMap<String, Attribute> aspectAttributes;
Dmitry Lomov15756522016-12-16 16:52:37 +00001592 private ImmutableList<AspectDescriptor> aspectDescriptors;
John Cater13263f72017-05-24 19:06:47 +02001593 private ToolchainContext toolchainContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001594
Michael Staib8824d5e2016-01-20 21:37:05 +00001595 Builder(
1596 AnalysisEnvironment env,
1597 Rule rule,
Dmitry Lomov15756522016-12-16 16:52:37 +00001598 ImmutableList<AspectDescriptor> aspectDescriptors,
Michael Staib8824d5e2016-01-20 21:37:05 +00001599 BuildConfiguration configuration,
Greg Estren9eb1cf02015-06-26 22:18:35 +00001600 BuildConfiguration hostConfiguration,
Michael Staib8824d5e2016-01-20 21:37:05 +00001601 PrerequisiteValidator prerequisiteValidator,
1602 ConfigurationFragmentPolicy configurationFragmentPolicy) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001603 this.env = Preconditions.checkNotNull(env);
1604 this.rule = Preconditions.checkNotNull(rule);
Dmitry Lomov15756522016-12-16 16:52:37 +00001605 this.aspectDescriptors = aspectDescriptors;
Michael Staib8824d5e2016-01-20 21:37:05 +00001606 this.configurationFragmentPolicy = Preconditions.checkNotNull(configurationFragmentPolicy);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001607 this.configuration = Preconditions.checkNotNull(configuration);
Greg Estren9eb1cf02015-06-26 22:18:35 +00001608 this.hostConfiguration = Preconditions.checkNotNull(hostConfiguration);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001609 this.prerequisiteValidator = prerequisiteValidator;
Michael Staib8824d5e2016-01-20 21:37:05 +00001610 reporter = new ErrorReporter(env, rule, getRuleClassNameForLogging());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001611 }
1612
1613 RuleContext build() {
1614 Preconditions.checkNotNull(prerequisiteMap);
1615 Preconditions.checkNotNull(configConditions);
1616 Preconditions.checkNotNull(visibility);
Nathan Harmatafcb17112016-04-13 16:56:58 +00001617 AttributeMap attributes = ConfiguredAttributeMapper.of(rule, configConditions);
1618 validateAttributes(attributes);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001619 ListMultimap<String, ConfiguredTarget> targetMap = createTargetMap();
1620 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap =
1621 createFilesetEntryMap(rule, configConditions);
Michael Staib8824d5e2016-01-20 21:37:05 +00001622 return new RuleContext(
1623 this,
Nathan Harmatafcb17112016-04-13 16:56:58 +00001624 attributes,
Michael Staib8824d5e2016-01-20 21:37:05 +00001625 targetMap,
1626 filesetEntryMap,
1627 configConditions,
1628 universalFragment,
1629 getRuleClassNameForLogging(),
John Cater13263f72017-05-24 19:06:47 +02001630 aspectAttributes != null ? aspectAttributes : ImmutableMap.<String, Attribute>of(),
1631 toolchainContext);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001632 }
1633
Nathan Harmatafcb17112016-04-13 16:56:58 +00001634 private void validateAttributes(AttributeMap attributes) {
1635 rule.getRuleClassObject().checkAttributesNonEmpty(rule, reporter, attributes);
1636 }
1637
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001638 Builder setVisibility(NestedSet<PackageSpecification> visibility) {
1639 this.visibility = visibility;
1640 return this;
1641 }
1642
1643 /**
1644 * Sets the prerequisites and checks their visibility. It also generates appropriate error or
1645 * warning messages and sets the error flag as appropriate.
1646 */
Greg Estrend5353252016-08-11 22:13:31 +00001647 Builder setPrerequisites(OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001648 this.prerequisiteMap = Preconditions.checkNotNull(prerequisiteMap);
1649 return this;
1650 }
1651
1652 /**
Carmi Grushko06f65f72015-11-02 22:42:24 +00001653 * Adds attributes which are defined by an Aspect (and not by RuleClass).
1654 */
1655 Builder setAspectAttributes(Map<String, Attribute> aspectAttributes) {
Dmitry Lomovace678e2015-12-16 15:10:20 +00001656 this.aspectAttributes = ImmutableMap.copyOf(aspectAttributes);
Carmi Grushko06f65f72015-11-02 22:42:24 +00001657 return this;
1658 }
1659
1660 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001661 * Sets the configuration conditions needed to determine which paths to follow for this
1662 * rule's configurable attributes.
1663 */
Lukacs Berki7894c182016-05-10 12:07:01 +00001664 Builder setConfigConditions(ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001665 this.configConditions = Preconditions.checkNotNull(configConditions);
1666 return this;
1667 }
1668
Greg Estrenc5a352f2015-11-13 17:25:36 +00001669 /**
1670 * Sets the fragment that can be legally accessed even when not explicitly declared.
1671 */
1672 Builder setUniversalFragment(Class<? extends BuildConfiguration.Fragment> fragment) {
1673 // TODO(bazel-team): Add this directly to ConfigurationFragmentPolicy, so we
1674 // don't need separate logic specifically for checking this fragment. The challenge is
1675 // that we need RuleClassProvider to figure out what this fragment is, and not every
1676 // call state that creates ConfigurationFragmentPolicy has access to that.
1677 this.universalFragment = fragment;
1678 return this;
1679 }
1680
Cal Peyserf296e872016-05-03 17:36:54 +00001681 /**
1682 * Sets a map that indicates which providers should be exported to skylark under the key
1683 * (map key). These provider types will also be exportable by skylark rules under (map key).
1684 */
1685 Builder setSkylarkProvidersRegistry(
1686 ImmutableBiMap<String, Class<? extends TransitiveInfoProvider>> skylarkProviderRegistry) {
Cal Peyserf296e872016-05-03 17:36:54 +00001687 return this;
1688 }
1689
John Cater13263f72017-05-24 19:06:47 +02001690 /** Sets the {@link ToolchainContext} used to access toolchains used by this rule. */
1691 Builder setToolchainContext(ToolchainContext toolchainContext) {
1692 this.toolchainContext = toolchainContext;
1693 return this;
1694 }
1695
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001696 private boolean validateFilesetEntry(FilesetEntry filesetEntry, ConfiguredTarget src) {
1697 if (src.getProvider(FilesetProvider.class) != null) {
1698 return true;
1699 }
1700 if (filesetEntry.isSourceFileset()) {
1701 return true;
1702 }
1703
1704 Target srcTarget = src.getTarget();
1705 if (!(srcTarget instanceof FileTarget)) {
1706 attributeError("entries", String.format(
1707 "Invalid 'srcdir' target '%s'. Must be another Fileset or package",
1708 srcTarget.getLabel()));
1709 return false;
1710 }
1711
1712 if (srcTarget instanceof OutputFile) {
1713 attributeWarning("entries", String.format("'srcdir' target '%s' is not an input file. "
1714 + "This forces the Fileset to be executed unconditionally",
1715 srcTarget.getLabel()));
1716 }
1717
1718 return true;
1719 }
1720
1721 /**
1722 * Determines and returns a map from attribute name to list of configured fileset entries, based
1723 * on a PrerequisiteMap instance.
1724 */
1725 private ListMultimap<String, ConfiguredFilesetEntry> createFilesetEntryMap(
Lukacs Berki7894c182016-05-10 12:07:01 +00001726 final Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001727 final ImmutableSortedKeyListMultimap.Builder<String, ConfiguredFilesetEntry> mapBuilder =
1728 ImmutableSortedKeyListMultimap.builder();
1729 for (Attribute attr : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001730 if (attr.getType() != BuildType.FILESET_ENTRY_LIST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001731 continue;
1732 }
1733 String attributeName = attr.getName();
1734 Map<Label, ConfiguredTarget> ctMap = new HashMap<>();
1735 for (ConfiguredTarget prerequisite : prerequisiteMap.get(attr)) {
Lukacs Berki8d41ca32016-08-26 08:50:48 +00001736 ctMap.put(AliasProvider.getDependencyLabel(prerequisite), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001737 }
1738 List<FilesetEntry> entries = ConfiguredAttributeMapper.of(rule, configConditions)
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001739 .get(attributeName, BuildType.FILESET_ENTRY_LIST);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001740 for (FilesetEntry entry : entries) {
1741 if (entry.getFiles() == null) {
1742 Label label = entry.getSrcLabel();
1743 ConfiguredTarget src = ctMap.get(label);
1744 if (!validateFilesetEntry(entry, src)) {
1745 continue;
1746 }
1747
1748 mapBuilder.put(attributeName, new ConfiguredFilesetEntry(entry, src));
1749 } else {
1750 ImmutableList.Builder<TransitiveInfoCollection> files = ImmutableList.builder();
1751 for (Label file : entry.getFiles()) {
1752 files.add(ctMap.get(file));
1753 }
1754 mapBuilder.put(attributeName, new ConfiguredFilesetEntry(entry, files.build()));
1755 }
1756 }
1757 }
1758 return mapBuilder.build();
1759 }
1760
1761 /**
1762 * Determines and returns a map from attribute name to list of configured targets.
1763 */
1764 private ImmutableSortedKeyListMultimap<String, ConfiguredTarget> createTargetMap() {
1765 ImmutableSortedKeyListMultimap.Builder<String, ConfiguredTarget> mapBuilder =
1766 ImmutableSortedKeyListMultimap.builder();
1767
1768 for (Map.Entry<Attribute, Collection<ConfiguredTarget>> entry :
1769 prerequisiteMap.asMap().entrySet()) {
1770 Attribute attribute = entry.getKey();
1771 if (attribute == null) {
1772 continue;
1773 }
lberki1cd6d1e2017-06-14 16:20:19 +02001774
1775 if (attribute.isSingleArtifact() && entry.getValue().size() > 1) {
1776 attributeError(attribute.getName(), "must contain a single dependency");
1777 continue;
1778 }
1779
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001780 if (attribute.isSilentRuleClassFilter()) {
1781 Predicate<RuleClass> filter = attribute.getAllowedRuleClassesPredicate();
1782 for (ConfiguredTarget configuredTarget : entry.getValue()) {
1783 Target prerequisiteTarget = configuredTarget.getTarget();
1784 if ((prerequisiteTarget instanceof Rule)
1785 && filter.apply(((Rule) prerequisiteTarget).getRuleClassObject())) {
1786 validateDirectPrerequisite(attribute, configuredTarget);
1787 mapBuilder.put(attribute.getName(), configuredTarget);
1788 }
1789 }
1790 } else {
1791 for (ConfiguredTarget configuredTarget : entry.getValue()) {
1792 validateDirectPrerequisite(attribute, configuredTarget);
1793 mapBuilder.put(attribute.getName(), configuredTarget);
1794 }
1795 }
1796 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001797 return mapBuilder.build();
1798 }
1799
Klaus Aehlig16a107d2017-05-31 18:02:43 +02001800 public void post(Postable event) {
1801 reporter.post(event);
1802 }
1803
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001804 public void reportError(Location location, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001805 reporter.reportError(location, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001806 }
1807
Florian Weikertb8a6a942015-09-25 12:36:08 +00001808 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001809 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001810 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001811 }
1812
Florian Weikertb8a6a942015-09-25 12:36:08 +00001813 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001814 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001815 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001816 }
1817
1818 public void reportWarning(Location location, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001819 reporter.reportWarning(location, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001820 }
1821
Florian Weikertb8a6a942015-09-25 12:36:08 +00001822 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001823 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001824 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001825 }
1826
Florian Weikertb8a6a942015-09-25 12:36:08 +00001827 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001828 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001829 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001830 }
1831
Googlere49cd592016-07-29 19:32:38 +00001832 private String badPrerequisiteMessage(String targetKind, ConfiguredTarget prerequisite,
1833 String reason, boolean isWarning) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001834 String msgPrefix = targetKind != null ? targetKind + " " : "";
1835 String msgReason = reason != null ? " (" + reason + ")" : "";
1836 if (isWarning) {
Googlere49cd592016-07-29 19:32:38 +00001837 return String.format(
Lukacs Berkic10120a2016-12-06 15:56:14 +00001838 "%s%s is unexpected here%s; continuing anyway",
1839 msgPrefix, AliasProvider.printLabelWithAliasChain(prerequisite),
Googlere49cd592016-07-29 19:32:38 +00001840 msgReason);
1841 }
Lukacs Berkic10120a2016-12-06 15:56:14 +00001842 return String.format("%s%s is misplaced here%s",
1843 msgPrefix, AliasProvider.printLabelWithAliasChain(prerequisite), msgReason);
Googlere49cd592016-07-29 19:32:38 +00001844 }
1845
1846 private void reportBadPrerequisite(Attribute attribute, String targetKind,
1847 ConfiguredTarget prerequisite, String reason, boolean isWarning) {
1848 String message = badPrerequisiteMessage(targetKind, prerequisite, reason, isWarning);
1849 if (isWarning) {
1850 attributeWarning(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001851 } else {
Googlere49cd592016-07-29 19:32:38 +00001852 attributeError(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001853 }
1854 }
1855
1856 private void validateDirectPrerequisiteType(ConfiguredTarget prerequisite,
1857 Attribute attribute) {
1858 Target prerequisiteTarget = prerequisite.getTarget();
1859 Label prerequisiteLabel = prerequisiteTarget.getLabel();
1860
1861 if (prerequisiteTarget instanceof Rule) {
1862 Rule prerequisiteRule = (Rule) prerequisiteTarget;
1863
1864 String reason = attribute.getValidityPredicate().checkValid(rule, prerequisiteRule);
1865 if (reason != null) {
1866 reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(),
Lukacs Berki7894c182016-05-10 12:07:01 +00001867 prerequisite, reason, false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001868 }
1869 }
1870
Yun Pengefd7ca12016-03-03 13:14:38 +00001871 if (prerequisiteTarget instanceof Rule) {
1872 validateRuleDependency(prerequisite, attribute);
1873 } else if (prerequisiteTarget instanceof FileTarget) {
1874 if (attribute.isStrictLabelCheckingEnabled()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001875 if (!attribute.getAllowedFileTypesPredicate()
1876 .apply(((FileTarget) prerequisiteTarget).getFilename())) {
1877 if (prerequisiteTarget instanceof InputFile
1878 && !((InputFile) prerequisiteTarget).getPath().exists()) {
1879 // Misplaced labels, no corresponding target exists
1880 if (attribute.getAllowedFileTypesPredicate().isNone()
1881 && !((InputFile) prerequisiteTarget).getFilename().contains(".")) {
1882 // There are no allowed files in the attribute but it's not a valid rule,
1883 // and the filename doesn't contain a dot --> probably a misspelled rule
1884 attributeError(attribute.getName(),
1885 "rule '" + prerequisiteLabel + "' does not exist");
1886 } else {
1887 attributeError(attribute.getName(),
1888 "target '" + prerequisiteLabel + "' does not exist");
1889 }
1890 } else {
1891 // The file exists but has a bad extension
Lukacs Berki7894c182016-05-10 12:07:01 +00001892 reportBadPrerequisite(attribute, "file", prerequisite,
Ulf Adams07dba942015-03-05 14:47:37 +00001893 "expected " + attribute.getAllowedFileTypesPredicate(), false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001894 }
1895 }
1896 }
1897 }
1898 }
1899
Michael Staib2707a882016-09-16 21:06:40 +00001900 /** Returns whether the context being constructed is for the evaluation of an aspect. */
1901 public boolean forAspect() {
Dmitry Lomov15756522016-12-16 16:52:37 +00001902 return !aspectDescriptors.isEmpty();
Michael Staib2707a882016-09-16 21:06:40 +00001903 }
1904
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001905 public Rule getRule() {
1906 return rule;
1907 }
1908
Michael Staib8824d5e2016-01-20 21:37:05 +00001909 /**
1910 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
1911 */
1912 public String getRuleClassNameForLogging() {
Dmitry Lomov15756522016-12-16 16:52:37 +00001913 if (aspectDescriptors.isEmpty()) {
1914 return rule.getRuleClass();
1915 }
1916
1917 return Joiner.on(",").join(aspectDescriptors) + " aspect on " + rule.getRuleClass();
Michael Staib8824d5e2016-01-20 21:37:05 +00001918 }
1919
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001920 public BuildConfiguration getConfiguration() {
1921 return configuration;
1922 }
1923
1924 /**
1925 * @return true if {@code rule} is visible from {@code prerequisite}.
1926 *
1927 * <p>This only computes the logic as implemented by the visibility system. The final decision
1928 * whether a dependency is allowed is made by
1929 * {@link ConfiguredRuleClassProvider.PrerequisiteValidator}, who is supposed to call this
1930 * method to determine whether a dependency is allowed as per visibility rules.
1931 */
1932 public boolean isVisible(TransitiveInfoCollection prerequisite) {
1933 return RuleContext.isVisible(rule, prerequisite);
1934 }
1935
1936 private void validateDirectPrerequisiteFileTypes(ConfiguredTarget prerequisite,
1937 Attribute attribute) {
1938 if (attribute.isSkipAnalysisTimeFileTypeCheck()) {
1939 return;
1940 }
1941 FileTypeSet allowedFileTypes = attribute.getAllowedFileTypesPredicate();
Ulf Adams788fd1a2015-03-12 13:54:09 +00001942 if (allowedFileTypes == null) {
1943 // It's not a label or label_list attribute.
1944 return;
1945 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001946 if (allowedFileTypes == FileTypeSet.ANY_FILE && !attribute.isNonEmpty()
1947 && !attribute.isSingleArtifact()) {
1948 return;
1949 }
1950
1951 // If we allow any file we still need to check if there are actually files generated
1952 // Note that this check only runs for ANY_FILE predicates if the attribute is NON_EMPTY
1953 // or SINGLE_ARTIFACT
1954 // If we performed this check when allowedFileTypes == NO_FILE this would
1955 // always throw an error in those cases
1956 if (allowedFileTypes != FileTypeSet.NO_FILE) {
1957 Iterable<Artifact> artifacts = prerequisite.getProvider(FileProvider.class)
1958 .getFilesToBuild();
1959 if (attribute.isSingleArtifact() && Iterables.size(artifacts) != 1) {
1960 attributeError(attribute.getName(),
1961 "'" + prerequisite.getLabel() + "' must produce a single file");
1962 return;
1963 }
1964 for (Artifact sourceArtifact : artifacts) {
1965 if (allowedFileTypes.apply(sourceArtifact.getFilename())) {
1966 return;
1967 }
1968 }
1969 attributeError(attribute.getName(), "'" + prerequisite.getLabel()
Michael Staib8824d5e2016-01-20 21:37:05 +00001970 + "' does not produce any " + getRuleClassNameForLogging() + " " + attribute.getName()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001971 + " files (expected " + allowedFileTypes + ")");
1972 }
1973 }
1974
dslomov7df85152017-08-01 20:47:59 +02001975 /**
dslomovc13bb392017-08-02 23:29:54 +02001976 * Because some rules still have to use allowedRuleClasses to do rule dependency validation. A
1977 * dependency is valid if it is from a rule in allowedRuledClasses, OR if all of the providers
1978 * in requiredProviders are provided by the target.
dslomov7df85152017-08-01 20:47:59 +02001979 */
1980 private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) {
dslomov7df85152017-08-01 20:47:59 +02001981
dslomovc13bb392017-08-02 23:29:54 +02001982 Set<String> unfulfilledRequirements = new LinkedHashSet<>();
1983 if (checkRuleDependencyClass(prerequisite, attribute, unfulfilledRequirements)) {
1984 return;
1985 }
1986
1987 if (checkRuleDependencyClassWarnings(prerequisite, attribute)) {
1988 return;
1989 }
1990
1991 if (checkRuleDependencyMandatoryProviders(prerequisite, attribute, unfulfilledRequirements)) {
1992 return;
1993 }
1994
1995 // not allowed rule class and some mandatory providers missing => reject.
1996 if (!unfulfilledRequirements.isEmpty()) {
1997 attributeError(
1998 attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
1999 }
2000 }
2001
2002 /** Check if prerequisite should be allowed based on its rule class. */
2003 private boolean checkRuleDependencyClass(
2004 ConfiguredTarget prerequisite, Attribute attribute, Set<String> unfulfilledRequirements) {
dslomovc32e1b12017-07-31 19:23:52 +02002005 if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
dslomovc13bb392017-08-02 23:29:54 +02002006 if (attribute
2007 .getAllowedRuleClassesPredicate()
2008 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002009 // prerequisite has an allowed rule class => accept.
dslomovc13bb392017-08-02 23:29:54 +02002010 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002011 }
2012 // remember that the rule class that was not allowed;
2013 // but maybe prerequisite provides required providers? do not reject yet.
dslomovc13bb392017-08-02 23:29:54 +02002014 unfulfilledRequirements.add(
dslomovc32e1b12017-07-31 19:23:52 +02002015 badPrerequisiteMessage(
dslomovc13bb392017-08-02 23:29:54 +02002016 prerequisite.getTarget().getTargetKind(),
dslomovc32e1b12017-07-31 19:23:52 +02002017 prerequisite,
2018 "expected " + attribute.getAllowedRuleClassesPredicate(),
dslomovc13bb392017-08-02 23:29:54 +02002019 false));
dslomovc32e1b12017-07-31 19:23:52 +02002020 }
dslomovc13bb392017-08-02 23:29:54 +02002021 return false;
2022 }
dslomovc32e1b12017-07-31 19:23:52 +02002023
dslomovc13bb392017-08-02 23:29:54 +02002024 /**
2025 * Check if prerequisite should be allowed with warning based on its rule class.
2026 *
2027 * <p>If yes, also issues said warning.
2028 */
2029 private boolean checkRuleDependencyClassWarnings(
2030 ConfiguredTarget prerequisite, Attribute attribute) {
2031 if (attribute
2032 .getAllowedRuleClassesWarningPredicate()
2033 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002034 Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate();
dslomovc13bb392017-08-02 23:29:54 +02002035 reportBadPrerequisite(
2036 attribute,
2037 prerequisite.getTarget().getTargetKind(),
2038 prerequisite,
dslomovc32e1b12017-07-31 19:23:52 +02002039 allowedRuleClasses == Predicates.<RuleClass>alwaysTrue()
dslomovde965ac2017-07-31 21:07:51 +02002040 ? null
2041 : "expected " + allowedRuleClasses,
dslomovc32e1b12017-07-31 19:23:52 +02002042 true);
2043 // prerequisite has a rule class allowed with a warning => accept, emitting a warning.
dslomovc13bb392017-08-02 23:29:54 +02002044 return true;
2045 }
2046 return false;
2047 }
2048
2049 /** Check if prerequisite should be allowed based on required providers on the attribute. */
2050 private boolean checkRuleDependencyMandatoryProviders(
2051 ConfiguredTarget prerequisite, Attribute attribute, Set<String> unfulfilledRequirements) {
2052 RequiredProviders requiredProviders = attribute.getRequiredProviders();
2053
2054 if (requiredProviders.acceptsAny()) {
2055 // If no required providers specified, we do not know if we should accept.
2056 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002057 }
2058
dslomovc13bb392017-08-02 23:29:54 +02002059 if (prerequisite.satisfies(requiredProviders)) {
2060 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002061 }
2062
dslomovc13bb392017-08-02 23:29:54 +02002063 unfulfilledRequirements.add(
2064 String.format(
2065 "'%s' does not have mandatory providers: %s",
2066 prerequisite.getLabel(),
2067 prerequisite.missingProviders(requiredProviders).getDescription()));
dslomovc32e1b12017-07-31 19:23:52 +02002068
dslomovc13bb392017-08-02 23:29:54 +02002069 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002070 }
2071
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002072 private void validateDirectPrerequisite(Attribute attribute, ConfiguredTarget prerequisite) {
2073 validateDirectPrerequisiteType(prerequisite, attribute);
2074 validateDirectPrerequisiteFileTypes(prerequisite, attribute);
Greg Estren875c7a72015-09-24 19:57:54 +00002075 if (attribute.performPrereqValidatorCheck()) {
Ulf Adams0b638972015-09-08 13:25:35 +00002076 prerequisiteValidator.validate(this, prerequisite, attribute);
2077 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002078 }
2079 }
2080
Florian Weikertb8a6a942015-09-25 12:36:08 +00002081 /**
2082 * Helper class for reporting errors and warnings.
2083 */
2084 public static final class ErrorReporter implements RuleErrorConsumer {
2085 private final AnalysisEnvironment env;
2086 private final Rule rule;
Michael Staib8824d5e2016-01-20 21:37:05 +00002087 private final String ruleClassNameForLogging;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002088
Michael Staib8824d5e2016-01-20 21:37:05 +00002089 ErrorReporter(AnalysisEnvironment env, Rule rule, String ruleClassNameForLogging) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002090 this.env = env;
2091 this.rule = rule;
Michael Staib8824d5e2016-01-20 21:37:05 +00002092 this.ruleClassNameForLogging = ruleClassNameForLogging;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002093 }
2094
2095 public void reportError(Location location, String message) {
2096 env.getEventHandler().handle(Event.error(location, message));
2097 }
2098
Klaus Aehlig16a107d2017-05-31 18:02:43 +02002099 public void post(Postable event) {
2100 env.getEventHandler().post(event);
2101 }
2102
Florian Weikertb8a6a942015-09-25 12:36:08 +00002103 @Override
2104 public void ruleError(String message) {
2105 reportError(rule.getLocation(), prefixRuleMessage(message));
2106 }
2107
2108 @Override
2109 public void attributeError(String attrName, String message) {
Florian Weikert5c679342015-11-04 16:53:59 +00002110 reportError(rule.getAttributeLocation(attrName), completeAttributeMessage(attrName, message));
Florian Weikertb8a6a942015-09-25 12:36:08 +00002111 }
2112
2113 public void reportWarning(Location location, String message) {
2114 env.getEventHandler().handle(Event.warn(location, message));
2115 }
2116
2117 @Override
2118 public void ruleWarning(String message) {
2119 env.getEventHandler().handle(Event.warn(rule.getLocation(), prefixRuleMessage(message)));
2120 }
2121
2122 @Override
2123 public void attributeWarning(String attrName, String message) {
Florian Weikert5c679342015-11-04 16:53:59 +00002124 reportWarning(
2125 rule.getAttributeLocation(attrName), completeAttributeMessage(attrName, message));
Florian Weikertb8a6a942015-09-25 12:36:08 +00002126 }
2127
2128 private String prefixRuleMessage(String message) {
Michael Staib8824d5e2016-01-20 21:37:05 +00002129 return String.format(
2130 "in %s rule %s: %s", getRuleClassNameForLogging(), rule.getLabel(), message);
Florian Weikertb8a6a942015-09-25 12:36:08 +00002131 }
2132
2133 private String maskInternalAttributeNames(String name) {
2134 return Attribute.isImplicit(name) ? "(an implicit dependency)" : name;
2135 }
2136
2137 /**
2138 * Prefixes the given message with details about the rule and appends details about the macro
2139 * that created this rule, if applicable.
2140 */
2141 private String completeAttributeMessage(String attrName, String message) {
2142 // Appends a note to the given message if the offending rule was created by a macro.
2143 String macroMessageAppendix =
Florian Weikert5c679342015-11-04 16:53:59 +00002144 rule.wasCreatedByMacro()
Florian Weikertb8a6a942015-09-25 12:36:08 +00002145 ? String.format(
2146 ". Since this rule was created by the macro '%s', the error might have been "
2147 + "caused by the macro implementation in %s",
Florian Weikert5c679342015-11-04 16:53:59 +00002148 getGeneratorFunction(), rule.getAttributeLocationWithoutMacro(attrName))
Florian Weikertb8a6a942015-09-25 12:36:08 +00002149 : "";
2150
2151 return String.format("in %s attribute of %s rule %s: %s%s",
Michael Staib8824d5e2016-01-20 21:37:05 +00002152 maskInternalAttributeNames(attrName), getRuleClassNameForLogging(), rule.getLabel(),
2153 message, macroMessageAppendix);
2154 }
2155
2156 /**
2157 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
2158 */
2159 private String getRuleClassNameForLogging() {
2160 return ruleClassNameForLogging;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002161 }
2162
Florian Weikertb8a6a942015-09-25 12:36:08 +00002163 private String getGeneratorFunction() {
2164 return (String) rule.getAttributeContainer().getAttr("generator_function");
2165 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002166 }
2167}