blob: e17f74a21aa401a03c7a991614b3c5354cc32852 [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;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010041import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
Ulf Adamsc272e0f2015-04-22 19:56:21 +000042import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
44import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
Greg Estren66cadd32016-08-05 21:07:02 +000045import com.google.devtools.build.lib.analysis.config.BuildOptions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
Florian Weikert3f8aac92015-09-07 12:06:02 +000047import com.google.devtools.build.lib.analysis.config.FragmentCollection;
gregcef2c1e832017-09-12 23:10:38 +020048import com.google.devtools.build.lib.analysis.config.PatchTransition;
gregce593f7f92017-09-19 02:02:21 +020049import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
ulfjacke8a3fea2017-08-09 11:28:19 +020050import com.google.devtools.build.lib.analysis.fileset.FilesetProvider;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000051import com.google.devtools.build.lib.cmdline.Label;
dslomovfd62e762017-09-19 16:55:53 +020052import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010053import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap;
54import com.google.devtools.build.lib.collect.nestedset.NestedSet;
55import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
56import com.google.devtools.build.lib.events.Event;
Klaus Aehlig16a107d2017-05-31 18:02:43 +020057import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058import com.google.devtools.build.lib.events.Location;
Dmitry Lomov15756522016-12-16 16:52:37 +000059import com.google.devtools.build.lib.packages.AspectDescriptor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010060import com.google.devtools.build.lib.packages.Attribute;
61import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
62import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
63import com.google.devtools.build.lib.packages.AttributeMap;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000064import com.google.devtools.build.lib.packages.BuildType;
Michael Staibb51251e2015-09-29 23:31:51 +000065import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010066import com.google.devtools.build.lib.packages.FileTarget;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000067import com.google.devtools.build.lib.packages.FilesetEntry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010068import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
dslomovde965ac2017-07-31 21:07:51 +020069import com.google.devtools.build.lib.packages.Info;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010070import com.google.devtools.build.lib.packages.InputFile;
dslomovde965ac2017-07-31 21:07:51 +020071import com.google.devtools.build.lib.packages.NativeProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010072import com.google.devtools.build.lib.packages.OutputFile;
73import com.google.devtools.build.lib.packages.PackageSpecification;
74import com.google.devtools.build.lib.packages.RawAttributeMapper;
dslomovc13bb392017-08-02 23:29:54 +020075import com.google.devtools.build.lib.packages.RequiredProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076import com.google.devtools.build.lib.packages.Rule;
77import com.google.devtools.build.lib.packages.RuleClass;
Chris Parsons4dfb22c2016-05-23 17:39:42 +000078import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.lib.packages.RuleErrorConsumer;
80import com.google.devtools.build.lib.packages.Target;
81import com.google.devtools.build.lib.packages.TargetUtils;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010082import 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;
93import java.util.HashMap;
94import java.util.HashSet;
lberki3c1c8e92017-07-13 12:25:47 +020095import java.util.LinkedHashMap;
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +000096import java.util.LinkedHashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010097import java.util.List;
98import java.util.Map;
99import java.util.Set;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100100import javax.annotation.Nullable;
101
102/**
Lukacs Berki2300cd62016-05-19 11:06:37 +0000103 * The totality of data available during the analysis of a rule.
Janak Ramakrishnan81c5bd82016-03-22 20:07:43 +0000104 *
105 * <p>These objects should not outlast the analysis phase. Do not pass them to {@link Action}
106 * objects or other persistent objects. There are internal tests to ensure that RuleContext objects
107 * are not persisted that check the name of this class, so update those tests if you change this
108 * class's name.
Lukacs Berki2300cd62016-05-19 11:06:37 +0000109 *
ulfjack26d0e492017-08-07 13:42:33 +0200110 * @see com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100111 */
112public final class RuleContext extends TargetContext
113 implements ActionConstructionContext, ActionRegistry, RuleErrorConsumer {
Carmi Grushko33aa3062016-11-11 02:45:29 +0000114
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100115 /**
116 * The configured version of FilesetEntry.
117 */
118 @Immutable
119 public static final class ConfiguredFilesetEntry {
120 private final FilesetEntry entry;
121 private final TransitiveInfoCollection src;
122 private final ImmutableList<TransitiveInfoCollection> files;
123
124 ConfiguredFilesetEntry(FilesetEntry entry, TransitiveInfoCollection src) {
125 this.entry = entry;
126 this.src = src;
127 this.files = null;
128 }
129
130 ConfiguredFilesetEntry(FilesetEntry entry, ImmutableList<TransitiveInfoCollection> files) {
131 this.entry = entry;
132 this.src = null;
133 this.files = files;
134 }
135
136 public FilesetEntry getEntry() {
137 return entry;
138 }
139
140 public TransitiveInfoCollection getSrc() {
141 return src;
142 }
143
144 /**
145 * Targets from FilesetEntry.files, or null if the user omitted it.
146 */
147 @Nullable
Ulf Adams10993fe2016-04-19 12:55:12 +0000148 public ImmutableList<TransitiveInfoCollection> getFiles() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100149 return files;
150 }
151 }
152
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000153 private static final String HOST_CONFIGURATION_PROGRESS_TAG = "for host";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100154
155 private final Rule rule;
Dmitry Lomov15756522016-12-16 16:52:37 +0000156 private final ImmutableList<AspectDescriptor> aspectDescriptors;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100157 private final ListMultimap<String, ConfiguredTarget> targetMap;
158 private final ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap;
Lukacs Berki7894c182016-05-10 12:07:01 +0000159 private final ImmutableMap<Label, ConfigMatchingProvider> configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000160 private final AspectAwareAttributeMapper attributes;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100161 private final ImmutableSet<String> features;
Michael Staib8824d5e2016-01-20 21:37:05 +0000162 private final String ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000163 private final BuildConfiguration hostConfiguration;
Michael Staibb51251e2015-09-29 23:31:51 +0000164 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
Greg Estrenc5a352f2015-11-13 17:25:36 +0000165 private final Class<? extends BuildConfiguration.Fragment> universalFragment;
Florian Weikertb8a6a942015-09-25 12:36:08 +0000166 private final ErrorReporter reporter;
John Cater13263f72017-05-24 19:06:47 +0200167 @Nullable private final ToolchainContext toolchainContext;
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000168
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100169 private ActionOwner actionOwner;
170
171 /* lazily computed cache for Make variables, computed from the above. See get... method */
172 private transient ConfigurationMakeVariableContext configurationMakeVariableContext = null;
173
Dmitry Lomovace678e2015-12-16 15:10:20 +0000174 private RuleContext(
175 Builder builder,
Nathan Harmatafcb17112016-04-13 16:56:58 +0000176 AttributeMap attributes,
Dmitry Lomovace678e2015-12-16 15:10:20 +0000177 ListMultimap<String, ConfiguredTarget> targetMap,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100178 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap,
Lukacs Berki7894c182016-05-10 12:07:01 +0000179 ImmutableMap<Label, ConfigMatchingProvider> configConditions,
Greg Estrenc5a352f2015-11-13 17:25:36 +0000180 Class<? extends BuildConfiguration.Fragment> universalFragment,
Michael Staib8824d5e2016-01-20 21:37:05 +0000181 String ruleClassNameForLogging,
John Cater13263f72017-05-24 19:06:47 +0200182 ImmutableMap<String, Attribute> aspectAttributes,
183 @Nullable ToolchainContext toolchainContext) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100184 super(builder.env, builder.rule, builder.configuration, builder.prerequisiteMap.get(null),
185 builder.visibility);
186 this.rule = builder.rule;
Dmitry Lomov15756522016-12-16 16:52:37 +0000187 this.aspectDescriptors = builder.aspectDescriptors;
Michael Staibb51251e2015-09-29 23:31:51 +0000188 this.configurationFragmentPolicy = builder.configurationFragmentPolicy;
Greg Estrenc5a352f2015-11-13 17:25:36 +0000189 this.universalFragment = universalFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100190 this.targetMap = targetMap;
191 this.filesetEntryMap = filesetEntryMap;
192 this.configConditions = configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000193 this.attributes = new AspectAwareAttributeMapper(attributes, aspectAttributes);
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000194 this.features = getEnabledFeatures();
Michael Staib8824d5e2016-01-20 21:37:05 +0000195 this.ruleClassNameForLogging = ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000196 this.hostConfiguration = builder.hostConfiguration;
Florian Weikertb8a6a942015-09-25 12:36:08 +0000197 reporter = builder.reporter;
John Cater13263f72017-05-24 19:06:47 +0200198 this.toolchainContext = toolchainContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100199 }
200
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000201 private ImmutableSet<String> getEnabledFeatures() {
202 Set<String> globallyEnabled = new HashSet<>();
203 Set<String> globallyDisabled = new HashSet<>();
204 parseFeatures(getConfiguration().getDefaultFeatures(), globallyEnabled, globallyDisabled);
Googler21da7262015-09-19 00:29:50 +0000205 for (ImmutableMap.Entry<Class<? extends Fragment>, Fragment> entry :
206 getConfiguration().getAllFragments().entrySet()) {
Michael Staibff66c192016-01-14 22:40:37 +0000207 if (isLegalFragment(entry.getKey())) {
Googler21da7262015-09-19 00:29:50 +0000208 globallyEnabled.addAll(entry.getValue().configurationEnabledFeatures(this));
209 }
210 }
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000211 Set<String> packageEnabled = new HashSet<>();
212 Set<String> packageDisabled = new HashSet<>();
213 parseFeatures(getRule().getPackage().getFeatures(), packageEnabled, packageDisabled);
214 Set<String> packageFeatures =
215 Sets.difference(Sets.union(globallyEnabled, packageEnabled), packageDisabled);
216 Set<String> ruleFeatures = packageFeatures;
217 if (attributes().has("features", Type.STRING_LIST)) {
218 Set<String> ruleEnabled = new HashSet<>();
219 Set<String> ruleDisabled = new HashSet<>();
220 parseFeatures(attributes().get("features", Type.STRING_LIST), ruleEnabled, ruleDisabled);
221 ruleFeatures = Sets.difference(Sets.union(packageFeatures, ruleEnabled), ruleDisabled);
222 }
223 return ImmutableSortedSet.copyOf(Sets.difference(ruleFeatures, globallyDisabled));
224 }
225
226 private void parseFeatures(Iterable<String> features, Set<String> enabled, Set<String> disabled) {
227 for (String feature : features) {
228 if (feature.startsWith("-")) {
229 disabled.add(feature.substring(1));
230 } else if (feature.equals("no_layering_check")) {
231 // TODO(bazel-team): Remove once we do not have BUILD files left that contain
232 // 'no_layering_check'.
233 disabled.add(feature.substring(3));
234 } else {
235 enabled.add(feature);
236 }
237 }
238 }
239
dslomovfd62e762017-09-19 16:55:53 +0200240 public RepositoryName getRepository() {
241 return rule.getRepository();
242 }
243
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100244 @Override
dslomovfd62e762017-09-19 16:55:53 +0200245 public Root getBinDirectory() {
246 return getConfiguration().getBinDirectory(rule.getRepository());
247 }
248
249 @Override
250 public Root getMiddlemanDirectory() {
251 return getConfiguration().getMiddlemanDirectory(rule.getRepository());
252 }
253
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100254 public Rule getRule() {
255 return rule;
256 }
257
258 /**
Michael Staib8824d5e2016-01-20 21:37:05 +0000259 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
260 */
261 public String getRuleClassNameForLogging() {
262 return ruleClassNameForLogging;
263 }
264
265 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +0000266 * Returns the workspace name for the rule.
267 */
268 public String getWorkspaceName() {
kchodorow85ae1902017-04-22 15:07:22 -0400269 return rule.getRepository().strippedName();
Kristina Chodorow91876f02015-02-27 17:14:12 +0000270 }
271
272 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100273 * The configuration conditions that trigger this rule's configurable attributes.
274 */
gregce593f7f92017-09-19 02:02:21 +0200275 public ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100276 return configConditions;
277 }
278
279 /**
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000280 * Returns the host configuration for this rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100281 */
282 public BuildConfiguration getHostConfiguration() {
Greg Estren9eb1cf02015-06-26 22:18:35 +0000283 return hostConfiguration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100284 }
285
286 /**
Dmitry Lomovace678e2015-12-16 15:10:20 +0000287 * Attributes from aspects.
288 */
289 public ImmutableMap<String, Attribute> getAspectAttributes() {
Greg Estren7f534232016-12-01 21:38:25 +0000290 return attributes.getAspectAttributes();
Dmitry Lomovace678e2015-12-16 15:10:20 +0000291 }
292
293 /**
Dmitry Lomov503c2f72017-02-23 08:55:47 +0000294 * All aspects applied to the rule.
295 */
296 public ImmutableList<AspectDescriptor> getAspectDescriptors() {
297 return aspectDescriptors;
298 }
299
300 /**
Greg Estren7f534232016-12-01 21:38:25 +0000301 * Accessor for the attributes of the rule and its aspects.
302 *
303 * <p>The rule's native attributes can be queried both on their structure / existence and values
304 * Aspect attributes can only be queried on their structure.
305 *
306 * <p>This should be the sole interface for reading rule/aspect attributes in {@link RuleContext}.
307 * Don't expose other access points through new public methods.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100308 */
309 public AttributeMap attributes() {
310 return attributes;
311 }
312
313 /**
314 * Returns whether this instance is known to have errors at this point during analysis. Do not
315 * call this method after the initializationHook has returned.
316 */
317 public boolean hasErrors() {
318 return getAnalysisEnvironment().hasErrors();
319 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000320
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000321 /**
322 * No-op if {@link #hasErrors} is false, throws {@link RuleErrorException} if it is true.
323 * This provides a convenience to early-exit of configured target creation if there are errors.
324 */
325 public void assertNoErrors() throws RuleErrorException {
326 if (hasErrors()) {
327 throw new RuleErrorException();
328 }
329 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100330
331 /**
332 * Returns an immutable map from attribute name to list of configured targets for that attribute.
333 */
334 public ListMultimap<String, ? extends TransitiveInfoCollection> getConfiguredTargetMap() {
335 return targetMap;
336 }
337
338 /**
339 * Returns an immutable map from attribute name to list of fileset entries.
340 */
341 public ListMultimap<String, ConfiguredFilesetEntry> getFilesetEntryMap() {
342 return filesetEntryMap;
343 }
344
345 @Override
346 public ActionOwner getActionOwner() {
347 if (actionOwner == null) {
Dmitry Lomov15756522016-12-16 16:52:37 +0000348 actionOwner = createActionOwner(rule, aspectDescriptors, getConfiguration());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100349 }
350 return actionOwner;
351 }
352
353 /**
354 * Returns a configuration fragment for this this target.
355 */
356 @Nullable
Florian Weikert3f8aac92015-09-07 12:06:02 +0000357 public <T extends Fragment> T getFragment(Class<T> fragment, ConfigurationTransition config) {
Florian Weikertd2a24612015-09-07 14:35:23 +0000358 return getFragment(fragment, fragment.getSimpleName(), "", config);
359 }
360
361 @Nullable
362 protected <T extends Fragment> T getFragment(Class<T> fragment, String name,
363 String additionalErrorMessage, ConfigurationTransition config) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100364 // TODO(bazel-team): The fragments can also be accessed directly through BuildConfiguration.
365 // Can we lock that down somehow?
Florian Weikert3f8aac92015-09-07 12:06:02 +0000366 Preconditions.checkArgument(isLegalFragment(fragment, config),
Florian Weikertd2a24612015-09-07 14:35:23 +0000367 "%s has to declare '%s' as a required fragment "
368 + "in %s configuration in order to access it.%s",
Michael Staib8824d5e2016-01-20 21:37:05 +0000369 getRuleClassNameForLogging(), name, FragmentCollection.getConfigurationName(config),
Florian Weikertd2a24612015-09-07 14:35:23 +0000370 additionalErrorMessage);
Florian Weikert1c2eeac2015-10-28 10:00:53 +0000371 return getConfiguration(config).getFragment(fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100372 }
373
Florian Weikert082c0542015-08-06 10:24:29 +0000374 @Nullable
Florian Weikert3f8aac92015-09-07 12:06:02 +0000375 public <T extends Fragment> T getFragment(Class<T> fragment) {
376 // NONE means target configuration.
377 return getFragment(fragment, ConfigurationTransition.NONE);
Florian Weikert082c0542015-08-06 10:24:29 +0000378 }
379
Florian Weikert3f8aac92015-09-07 12:06:02 +0000380 @Nullable
381 public Fragment getSkylarkFragment(String name, ConfigurationTransition config) {
Florian Weikert1c2eeac2015-10-28 10:00:53 +0000382 Class<? extends Fragment> fragmentClass =
383 getConfiguration(config).getSkylarkFragmentByName(name);
Florian Weikertd2a24612015-09-07 14:35:23 +0000384 if (fragmentClass == null) {
385 return null;
386 }
387 return getFragment(fragmentClass, name,
388 String.format(
389 " Please update the '%1$sfragments' argument of the rule definition "
390 + "(for example: %1$sfragments = [\"%2$s\"])",
391 (config == ConfigurationTransition.HOST) ? "host_" : "", name),
392 config);
Florian Weikert3f8aac92015-09-07 12:06:02 +0000393 }
394
395 public ImmutableCollection<String> getSkylarkFragmentNames(ConfigurationTransition config) {
396 return getConfiguration(config).getSkylarkFragmentNames();
397 }
398
399 public <T extends Fragment> boolean isLegalFragment(
400 Class<T> fragment, ConfigurationTransition config) {
Greg Estrenc5a352f2015-11-13 17:25:36 +0000401 return fragment == universalFragment
cpeysera399b7c2017-09-19 18:19:27 +0200402 || fragment == PlatformConfiguration.class
Greg Estrenc5a352f2015-11-13 17:25:36 +0000403 || configurationFragmentPolicy.isLegalConfigurationFragment(fragment, config);
Florian Weikert082c0542015-08-06 10:24:29 +0000404 }
405
Ulf Adamsea11fc52015-08-04 14:23:58 +0000406 public <T extends Fragment> boolean isLegalFragment(Class<T> fragment) {
Florian Weikert3f8aac92015-09-07 12:06:02 +0000407 // NONE means target configuration.
408 return isLegalFragment(fragment, ConfigurationTransition.NONE);
409 }
Florian Weikertd2a24612015-09-07 14:35:23 +0000410
Florian Weikert3f8aac92015-09-07 12:06:02 +0000411 protected BuildConfiguration getConfiguration(ConfigurationTransition config) {
412 return config.equals(ConfigurationTransition.HOST) ? hostConfiguration : getConfiguration();
Ulf Adamsea11fc52015-08-04 14:23:58 +0000413 }
414
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100415 @Override
416 public ArtifactOwner getOwner() {
417 return getAnalysisEnvironment().getOwner();
418 }
419
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000420 public ImmutableList<Artifact> getBuildInfo(BuildInfoKey key) throws InterruptedException {
Googler38ad0bf2016-07-01 05:00:14 +0000421 return getAnalysisEnvironment().getBuildInfo(this, key, getConfiguration());
Ulf Adamsc272e0f2015-04-22 19:56:21 +0000422 }
423
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000424 @VisibleForTesting
Carmi Grushko33aa3062016-11-11 02:45:29 +0000425 public static ActionOwner createActionOwner(
426 Rule rule,
Dmitry Lomov15756522016-12-16 16:52:37 +0000427 ImmutableList<AspectDescriptor> aspectDescriptors,
Carmi Grushko33aa3062016-11-11 02:45:29 +0000428 BuildConfiguration configuration) {
Carmi Grushko4665e702016-11-09 21:51:27 +0000429 return ActionOwner.create(
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000430 rule.getLabel(),
Dmitry Lomov15756522016-12-16 16:52:37 +0000431 aspectDescriptors,
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000432 rule.getLocation(),
433 configuration.getMnemonic(),
434 rule.getTargetKind(),
435 configuration.checksum(),
Klaus Aehligce1c36d2017-07-13 13:22:44 +0200436 configuration,
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000437 configuration.isHostConfiguration() ? HOST_CONFIGURATION_PROGRESS_TAG : null);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100438 }
439
440 @Override
Rumou Duan33bab462016-04-25 17:55:12 +0000441 public void registerAction(ActionAnalysisMetadata... action) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100442 getAnalysisEnvironment().registerAction(action);
443 }
444
445 /**
446 * Convenience function for subclasses to report non-attribute-specific
447 * errors in the current rule.
448 */
449 @Override
450 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000451 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100452 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000453
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000454 /**
455 * Convenience function to report non-attribute-specific errors in the current rule and then
456 * throw a {@link RuleErrorException}, immediately exiting the build invocation. Alternatively,
457 * invoke {@link #ruleError} instead to collect additional error information before ending the
458 * invocation.
459 */
460 public void throwWithRuleError(String message) throws RuleErrorException {
461 reporter.ruleError(message);
462 throw new RuleErrorException();
463 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100464
465 /**
466 * Convenience function for subclasses to report non-attribute-specific
467 * warnings in the current rule.
468 */
469 @Override
470 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000471 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100472 }
473
474 /**
475 * Convenience function for subclasses to report attribute-specific errors in
476 * the current rule.
477 *
478 * <p>If the name of the attribute starts with <code>$</code>
479 * it is replaced with a string <code>(an implicit dependency)</code>.
480 */
481 @Override
482 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000483 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100484 }
485
486 /**
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000487 * Convenience function to report attribute-specific errors in the current rule, and then throw a
488 * {@link RuleErrorException}, immediately exiting the build invocation. Alternatively, invoke
489 * {@link #attributeError} instead to collect additional error information before ending the
490 * invocation.
491 *
492 * <p>If the name of the attribute starts with <code>$</code>
493 * it is replaced with a string <code>(an implicit dependency)</code>.
494 */
Chris Parsonsf6a45fd2016-06-15 19:32:34 +0000495 public RuleErrorException throwWithAttributeError(String attrName, String message)
496 throws RuleErrorException {
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000497 reporter.attributeError(attrName, message);
498 throw new RuleErrorException();
499 }
500
501 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100502 * Like attributeError, but does not mark the configured target as errored.
503 *
504 * <p>If the name of the attribute starts with <code>$</code>
505 * it is replaced with a string <code>(an implicit dependency)</code>.
506 */
507 @Override
508 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000509 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100510 }
511
512 /**
513 * Returns an artifact beneath the root of either the "bin" or "genfiles"
514 * tree, whose path is based on the name of this target and the current
515 * configuration. The choice of which tree to use is based on the rule with
516 * which this target (which must be an OutputFile or a Rule) is associated.
517 */
518 public Artifact createOutputArtifact() {
519 return internalCreateOutputArtifact(getTarget());
520 }
521
522 /**
523 * Returns the output artifact of an {@link OutputFile} of this target.
524 *
525 * @see #createOutputArtifact()
526 */
527 public Artifact createOutputArtifact(OutputFile out) {
528 return internalCreateOutputArtifact(out);
529 }
530
531 /**
532 * Implementation for {@link #createOutputArtifact()} and
533 * {@link #createOutputArtifact(OutputFile)}. This is private so that
534 * {@link #createOutputArtifact(OutputFile)} can have a more specific
535 * signature.
536 */
537 private Artifact internalCreateOutputArtifact(Target target) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000538 Preconditions.checkState(
539 target.getLabel().getPackageIdentifier().equals(getLabel().getPackageIdentifier()),
540 "Creating output artifact for target '%s' in different package than the rule '%s' "
541 + "being analyzed", target.getLabel(), getLabel());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100542 Root root = getBinOrGenfilesDirectory();
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000543 return getPackageRelativeArtifact(target.getName(), root);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100544 }
545
546 /**
547 * Returns the root of either the "bin" or "genfiles"
548 * tree, based on this target and the current configuration.
549 * The choice of which tree to use is based on the rule with
550 * which this target (which must be an OutputFile or a Rule) is associated.
551 */
552 public Root getBinOrGenfilesDirectory() {
Kristina Chodorowba41c2d2016-10-10 17:21:24 +0000553 return rule.hasBinaryOutput()
554 ? getConfiguration().getBinDirectory(rule.getRepository())
555 : getConfiguration().getGenfilesDirectory(rule.getRepository());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100556 }
557
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000558 /**
559 * Creates an artifact in a directory that is unique to the package that contains the rule,
560 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
561 */
562 public Artifact getPackageRelativeArtifact(String relative, Root root) {
nharmatab4060b62017-04-04 17:11:39 +0000563 return getPackageRelativeArtifact(PathFragment.create(relative), root);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000564 }
565
566 /**
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000567 * 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 getBinArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000571 return getBinArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000572 }
573
574 public Artifact getBinArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000575 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000576 relative, getConfiguration().getBinDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000577 }
578
579 /**
580 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
581 * guaranteeing that it never clashes with artifacts created by rules in other packages.
582 */
583 public Artifact getGenfilesArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000584 return getGenfilesArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000585 }
586
587 public Artifact getGenfilesArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000588 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000589 relative, getConfiguration().getGenfilesDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000590 }
591
592 /**
Lukacs Berki21a04f22015-08-20 13:31:24 +0000593 * Returns an artifact that can be an output of shared actions. Only use when there is no other
594 * option.
595 *
596 * <p>This artifact can be created anywhere in the output tree, which, in addition to making
597 * sharing possible, opens up the possibility of action conflicts and makes it impossible to
598 * infer the label of the rule creating the artifact from the path of the artifact.
599 */
600 public Artifact getShareableArtifact(PathFragment rootRelativePath, Root root) {
601 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root);
602 }
603
604 /**
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000605 * Creates an artifact in a directory that is unique to the package that contains the rule,
606 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
607 */
608 public Artifact getPackageRelativeArtifact(PathFragment relative, Root root) {
609 return getDerivedArtifact(getPackageDirectory().getRelative(relative), root);
610 }
611
612 /**
613 * Returns the root-relative path fragment under which output artifacts of this rule should go.
614 *
615 * <p>Note that:
616 * <ul>
617 * <li>This doesn't guarantee that there are no clashes with rules in the same package.
618 * <li>If possible, {@link #getPackageRelativeArtifact(PathFragment, Root)} should be used
619 * instead of this method.
620 * </ul>
621 *
622 * Ideally, user-visible artifacts should all have corresponding output file targets, all others
623 * should go into a rule-specific directory.
624 * {@link #getUniqueDirectoryArtifact(String, PathFragment, Root)}) ensures that this is the case.
625 */
626 public PathFragment getPackageDirectory() {
Dmitry Lomove36a66c2017-02-17 14:48:48 +0000627 return getLabel().getPackageIdentifier().getSourceRoot();
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000628 }
629
630 /**
631 * Creates an artifact under a given root with the given root-relative path.
632 *
633 * <p>Verifies that it is in the root-relative directory corresponding to the package of the rule,
634 * thus ensuring that it doesn't clash with other artifacts generated by other rules using this
635 * method.
636 */
Ulf Adams3ab82f72015-09-04 12:10:53 +0000637 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000638 public Artifact getDerivedArtifact(PathFragment rootRelativePath, Root root) {
639 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
640 "Output artifact '%s' not under package directory '%s' for target '%s'",
641 rootRelativePath, getPackageDirectory(), getLabel());
642 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root);
643 }
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000644
645 /**
646 * Creates a TreeArtifact under a given root with the given root-relative path.
647 *
648 * <p>Verifies that it is in the root-relative directory corresponding to the package of the rule,
649 * thus ensuring that it doesn't clash with other artifacts generated by other rules using this
650 * method.
651 */
652 public Artifact getTreeArtifact(PathFragment rootRelativePath, Root root) {
653 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
654 "Output artifact '%s' not under package directory '%s' for target '%s'",
655 rootRelativePath, getPackageDirectory(), getLabel());
656 return getAnalysisEnvironment().getTreeArtifact(rootRelativePath, root);
657 }
658
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000659 /**
allevato060a4482017-03-30 20:45:52 +0000660 * Creates a tree artifact in a directory that is unique to the package that contains the rule,
661 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
662 */
663 public Artifact getPackageRelativeTreeArtifact(PathFragment relative, Root root) {
664 return getTreeArtifact(getPackageDirectory().getRelative(relative), root);
665 }
666
667 /**
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000668 * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
669 * clashes with artifacts created by other rules.
670 */
671 public Artifact getUniqueDirectoryArtifact(
672 String uniqueDirectory, String relative, Root root) {
nharmatab4060b62017-04-04 17:11:39 +0000673 return getUniqueDirectoryArtifact(uniqueDirectory, PathFragment.create(relative), root);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000674 }
675
Lukacs Berkid6e64242015-07-30 17:06:23 +0000676 /**
677 * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
678 * clashes with artifacts created by other rules.
679 */
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000680 public Artifact getUniqueDirectoryArtifact(
681 String uniqueDirectory, PathFragment relative, Root root) {
682 return getDerivedArtifact(getUniqueDirectory(uniqueDirectory).getRelative(relative), root);
683 }
684
Googler03083852015-12-06 18:31:53 +0000685 /**
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000686 * Returns true iff the rule, or any attached aspect, has an attribute with the given name and
687 * type.
688 */
689 public boolean isAttrDefined(String attrName, Type<?> type) {
Greg Estren7f534232016-12-01 21:38:25 +0000690 return attributes().has(attrName, type);
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000691 }
692
693 /**
Lukacs Berki8bdae762016-07-13 14:58:54 +0000694 * Returns the dependencies through a {@code LABEL_DICT_UNARY} attribute as a map from
695 * a string to a {@link TransitiveInfoCollection}.
696 */
697 public Map<String, TransitiveInfoCollection> getPrerequisiteMap(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +0000698 Preconditions.checkState(attributes().has(attributeName, BuildType.LABEL_DICT_UNARY));
Lukacs Berki8bdae762016-07-13 14:58:54 +0000699
700 ImmutableMap.Builder<String, TransitiveInfoCollection> result = ImmutableMap.builder();
701 Map<String, Label> dict = attributes().get(attributeName, BuildType.LABEL_DICT_UNARY);
702 Map<Label, ConfiguredTarget> labelToDep = new HashMap<>();
703 for (ConfiguredTarget dep : targetMap.get(attributeName)) {
704 labelToDep.put(dep.getLabel(), dep);
705 }
706
707 for (Map.Entry<String, Label> entry : dict.entrySet()) {
708 result.put(entry.getKey(), Preconditions.checkNotNull(labelToDep.get(entry.getValue())));
709 }
710
711 return result.build();
712 }
713
714 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100715 * Returns the list of transitive info collections that feed into this target through the
716 * specified attribute. Note that you need to specify the correct mode for the attribute,
717 * otherwise an assertion will be raised.
718 */
719 public List<? extends TransitiveInfoCollection> getPrerequisites(String attributeName,
720 Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +0000721 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000722 if ((mode == Mode.TARGET) && (attributeDefinition.hasSplitConfigurationTransition())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100723 // TODO(bazel-team): If you request a split-configured attribute in the target configuration,
724 // we return only the list of configured targets for the first architecture; this is for
725 // backwards compatibility with existing code in cases where the call to getPrerequisites is
726 // deeply nested and we can't easily inject the behavior we want. However, we should fix all
727 // such call sites.
728 checkAttribute(attributeName, Mode.SPLIT);
Googler59480b92016-07-22 17:06:40 +0000729 Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> map =
730 getSplitPrerequisites(attributeName);
dslomovde965ac2017-07-31 21:07:51 +0200731 return map.isEmpty() ? ImmutableList.of() : map.entrySet().iterator().next().getValue();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100732 }
733
734 checkAttribute(attributeName, mode);
735 return targetMap.get(attributeName);
736 }
737
738 /**
Googler59480b92016-07-22 17:06:40 +0000739 * Returns the a prerequisites keyed by the CPU of their configurations.
740 * If the split transition is not active (e.g. split() returned an empty
741 * list), the key is an empty Optional.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100742 */
Googler59480b92016-07-22 17:06:40 +0000743 public Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>>
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100744 getSplitPrerequisites(String attributeName) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100745 checkAttribute(attributeName, Mode.SPLIT);
746
Greg Estren7f534232016-12-01 21:38:25 +0000747 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
Greg Estren66cadd32016-08-05 21:07:02 +0000748 @SuppressWarnings("unchecked") // Attribute.java doesn't have the BuildOptions symbol.
749 SplitTransition<BuildOptions> transition =
750 (SplitTransition<BuildOptions>) attributeDefinition.getSplitTransition(rule);
751 List<ConfiguredTarget> deps = targetMap.get(attributeName);
752
753 List<BuildOptions> splitOptions = transition.split(getConfiguration().getOptions());
754 if (splitOptions.isEmpty()) {
Googler59480b92016-07-22 17:06:40 +0000755 // The split transition is not active. Defer the decision on which CPU to use.
Greg Estren66cadd32016-08-05 21:07:02 +0000756 return ImmutableMap.of(Optional.<String>absent(), deps);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100757 }
758
759 Set<String> cpus = new HashSet<>();
Greg Estren66cadd32016-08-05 21:07:02 +0000760 for (BuildOptions options : splitOptions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100761 // This method should only be called when the split config is enabled on the command line, in
762 // which case this cpu can't be null.
Ulf Adams111006e2016-09-12 15:57:06 +0000763 cpus.add(options.get(BuildConfiguration.Options.class).cpu);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100764 }
765
766 // Use an ImmutableListMultimap.Builder here to preserve ordering.
Googler59480b92016-07-22 17:06:40 +0000767 ImmutableListMultimap.Builder<Optional<String>, TransitiveInfoCollection> result =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100768 ImmutableListMultimap.builder();
Greg Estren66cadd32016-08-05 21:07:02 +0000769 for (TransitiveInfoCollection t : deps) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100770 if (t.getConfiguration() != null) {
Googler59480b92016-07-22 17:06:40 +0000771 result.put(Optional.of(t.getConfiguration().getCpu()), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100772 } else {
773 // Source files don't have a configuration, so we add them to all architecture entries.
774 for (String cpu : cpus) {
Googler59480b92016-07-22 17:06:40 +0000775 result.put(Optional.of(cpu), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100776 }
777 }
778 }
779 return Multimaps.asMap(result.build());
780 }
781
782 /**
783 * Returns the specified provider of the prerequisite referenced by the attribute in the
784 * argument. Note that you need to specify the correct mode for the attribute, otherwise an
gregce47d57852017-06-26 23:01:54 +0200785 * assertion will be raised. If the attribute is empty or it does not support the specified
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100786 * provider, returns null.
787 */
788 public <C extends TransitiveInfoProvider> C getPrerequisite(
789 String attributeName, Mode mode, Class<C> provider) {
790 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
791 return prerequisite == null ? null : prerequisite.getProvider(provider);
792 }
793
794 /**
795 * Returns the transitive info collection that feeds into this target through the specified
796 * attribute. Note that you need to specify the correct mode for the attribute, otherwise an
797 * assertion will be raised. Returns null if the attribute is empty.
798 */
799 public TransitiveInfoCollection getPrerequisite(String attributeName, Mode mode) {
800 checkAttribute(attributeName, mode);
801 List<? extends TransitiveInfoCollection> elements = targetMap.get(attributeName);
802 if (elements.size() > 1) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000803 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
804 + " produces more than one prerequisite");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100805 }
806 return elements.isEmpty() ? null : elements.get(0);
807 }
808
809 /**
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000810 * For a given attribute, returns all {@link TransitiveInfoProvider}s provided by targets
811 * of that attribute. Each {@link TransitiveInfoProvider} is keyed by the
812 * {@link BuildConfiguration} under which the provider was created.
813 */
814 public <C extends TransitiveInfoProvider> ImmutableListMultimap<BuildConfiguration, C>
815 getPrerequisitesByConfiguration(String attributeName, Mode mode, final Class<C> classType) {
816 AnalysisUtils.checkProvider(classType);
817 List<? extends TransitiveInfoCollection> transitiveInfoCollections =
818 getPrerequisites(attributeName, mode);
Chris Parsons0d7f0412016-04-29 20:35:44 +0000819
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000820 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
821 ImmutableListMultimap.builder();
822 for (TransitiveInfoCollection prerequisite : transitiveInfoCollections) {
823 C prerequisiteProvider = prerequisite.getProvider(classType);
824 if (prerequisiteProvider != null) {
825 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
826 }
827 }
828 return result.build();
829 }
830
831 /**
dslomovde965ac2017-07-31 21:07:51 +0200832 * For a given attribute, returns all declared provider provided by targets of that attribute.
833 * Each declared provider is keyed by the {@link BuildConfiguration} under which the provider was
834 * created.
dslomov4e9fa192017-07-12 14:59:07 +0200835 */
dslomovde965ac2017-07-31 21:07:51 +0200836 public <C extends Info>
837 ImmutableListMultimap<BuildConfiguration, C> getPrerequisitesByConfiguration(
838 String attributeName, Mode mode, final NativeProvider<C> provider) {
dslomov4e9fa192017-07-12 14:59:07 +0200839 List<? extends TransitiveInfoCollection> transitiveInfoCollections =
840 getPrerequisites(attributeName, mode);
841
842 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
843 ImmutableListMultimap.builder();
844 for (TransitiveInfoCollection prerequisite : transitiveInfoCollections) {
845 C prerequisiteProvider = prerequisite.get(provider);
846 if (prerequisiteProvider != null) {
847 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
848 }
849 }
850 return result.build();
851 }
852
853 /**
Chris Parsons0d7f0412016-04-29 20:35:44 +0000854 * For a given attribute, returns all {@link TransitiveInfoCollection}s provided by targets
855 * of that attribute. Each {@link TransitiveInfoCollection} is keyed by the
856 * {@link BuildConfiguration} under which the collection was created.
857 */
858 public ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection>
859 getPrerequisitesByConfiguration(String attributeName, Mode mode) {
860 List<? extends TransitiveInfoCollection> transitiveInfoCollections =
861 getPrerequisites(attributeName, mode);
862
863 ImmutableListMultimap.Builder<BuildConfiguration, TransitiveInfoCollection> result =
864 ImmutableListMultimap.builder();
865 for (TransitiveInfoCollection prerequisite : transitiveInfoCollections) {
866 result.put(prerequisite.getConfiguration(), prerequisite);
867 }
868 return result.build();
869 }
870
871 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100872 * Returns all the providers of the specified type that are listed under the specified attribute
873 * of this target in the BUILD file.
874 */
875 public <C extends TransitiveInfoProvider> Iterable<C> getPrerequisites(String attributeName,
876 Mode mode, final Class<C> classType) {
877 AnalysisUtils.checkProvider(classType);
878 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), classType);
879 }
880
881 /**
Sergio Campamafd931432016-12-09 21:47:35 +0000882 * Returns all the declared providers (native and Skylark) for the specified constructor under the
883 * specified attribute of this target in the BUILD file.
884 */
dslomovde965ac2017-07-31 21:07:51 +0200885 public <T extends Info> Iterable<T> getPrerequisites(
886 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
dslomov77baa4c2017-07-10 17:15:27 +0200887 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), skylarkKey);
Sergio Campamafd931432016-12-09 21:47:35 +0000888 }
889
890 /**
Sergio Campamae8cecd92016-12-13 18:49:28 +0000891 * Returns the declared provider (native and Skylark) for the specified constructor under the
892 * specified attribute of this target in the BUILD file. May return null if there is no
893 * TransitiveInfoCollection under the specified attribute.
894 */
895 @Nullable
dslomovde965ac2017-07-31 21:07:51 +0200896 public <T extends Info> T getPrerequisite(
897 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
Sergio Campamae8cecd92016-12-13 18:49:28 +0000898 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
899 return prerequisite == null ? null : prerequisite.get(skylarkKey);
900 }
901
902 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100903 * Returns all the providers of the specified type that are listed under the specified attribute
904 * of this target in the BUILD file, and that contain the specified provider.
905 */
906 public <C extends TransitiveInfoProvider> Iterable<? extends TransitiveInfoCollection>
907 getPrerequisitesIf(String attributeName, Mode mode, final Class<C> classType) {
908 AnalysisUtils.checkProvider(classType);
909 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
910 }
911
912 /**
dslomov73527c32017-07-27 17:35:46 +0200913 * Returns all the providers of the specified type that are listed under the specified attribute
914 * of this target in the BUILD file, and that contain the specified provider.
915 */
dslomovde965ac2017-07-31 21:07:51 +0200916 public <C extends Info> Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
917 String attributeName, Mode mode, final NativeProvider<C> classType) {
dslomov73527c32017-07-27 17:35:46 +0200918 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
919 }
920
921
922 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100923 * Returns the prerequisite referred to by the specified attribute. Also checks whether
924 * the attribute is marked as executable and that the target referred to can actually be
925 * executed.
926 *
927 * <p>The {@code mode} argument must match the configuration transition specified in the
928 * definition of the attribute.
929 *
930 * @param attributeName the name of the attribute
931 * @param mode the configuration transition of the attribute
932 *
933 * @return the {@link FilesToRunProvider} interface of the prerequisite.
934 */
Carmi Grushko802f39e2016-04-06 20:03:56 +0000935 @Nullable
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100936 public FilesToRunProvider getExecutablePrerequisite(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +0000937 Attribute ruleDefinition = attributes().getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100938
939 if (ruleDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000940 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100941 + " is not defined");
942 }
943 if (!ruleDefinition.isExecutable()) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000944 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100945 + " is not configured to be executable");
946 }
947
948 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
949 if (prerequisite == null) {
950 return null;
951 }
952
953 FilesToRunProvider result = prerequisite.getProvider(FilesToRunProvider.class);
954 if (result == null || result.getExecutable() == null) {
955 attributeError(
956 attributeName, prerequisite.getLabel() + " does not refer to a valid executable target");
957 }
958 return result;
959 }
960
ulfjack08ff9b82017-09-28 04:08:06 -0400961 public void initConfigurationMakeVariableContext(
962 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
963 Preconditions.checkState(configurationMakeVariableContext == null);
964 configurationMakeVariableContext =
965 new ConfigurationMakeVariableContext(
966 this, getRule().getPackage(), getConfiguration(), makeVariableSuppliers);
967 }
968
969 public void initConfigurationMakeVariableContext(MakeVariableSupplier... makeVariableSuppliers) {
970 initConfigurationMakeVariableContext(ImmutableList.copyOf(makeVariableSuppliers));
971 }
972
ulfjack07860132017-09-29 08:59:44 -0400973 public Expander getExpander(ConfigurationMakeVariableContext makeVariableContext) {
974 return new Expander(this, makeVariableContext);
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +0000975 }
976
ulfjack07860132017-09-29 08:59:44 -0400977 public Expander getExpander() {
978 return new Expander(this, getConfigurationMakeVariableContext());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100979 }
980
lberki6cd3b2d2017-05-05 09:18:48 +0200981 public ImmutableMap<String, String> getMakeVariables(Iterable<String> attributeNames) {
dslomov375f95b2017-08-21 12:52:41 +0200982 ArrayList<MakeVariableInfo> makeVariableInfos = new ArrayList<>();
lberki6cd3b2d2017-05-05 09:18:48 +0200983
984 for (String attributeName : attributeNames) {
985 // TODO(b/37567440): Remove this continue statement.
986 if (!attributes().has(attributeName)) {
987 continue;
988 }
dslomov375f95b2017-08-21 12:52:41 +0200989 Iterables.addAll(makeVariableInfos, getPrerequisites(
990 attributeName, Mode.DONT_CHECK, MakeVariableInfo.PROVIDER));
lberki6cd3b2d2017-05-05 09:18:48 +0200991 }
992
lberki3c1c8e92017-07-13 12:25:47 +0200993 LinkedHashMap<String, String> makeVariables = new LinkedHashMap<>();
dslomov375f95b2017-08-21 12:52:41 +0200994 for (MakeVariableInfo makeVariableInfo : makeVariableInfos) {
995 makeVariables.putAll(makeVariableInfo.getMakeVariables());
lberki6cd3b2d2017-05-05 09:18:48 +0200996 }
997
lberki3c1c8e92017-07-13 12:25:47 +0200998 return ImmutableMap.copyOf(makeVariables);
lberki6cd3b2d2017-05-05 09:18:48 +0200999 }
1000
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001001 /**
ulfjack08ff9b82017-09-28 04:08:06 -04001002 * Returns a cached context that maps Make variable names (string) to values (string) without any
1003 * extra {@link MakeVariableSupplier}.
hlopkoa4778052017-05-26 11:37:28 +02001004 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001005 public ConfigurationMakeVariableContext getConfigurationMakeVariableContext() {
1006 if (configurationMakeVariableContext == null) {
ulfjack08ff9b82017-09-28 04:08:06 -04001007 initConfigurationMakeVariableContext(ImmutableList.<MakeVariableSupplier>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001008 }
1009 return configurationMakeVariableContext;
1010 }
1011
John Cater13263f72017-05-24 19:06:47 +02001012 @Nullable
John Catereca28402017-05-17 21:44:12 +02001013 public ToolchainContext getToolchainContext() {
1014 return toolchainContext;
1015 }
1016
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001017 private void checkAttribute(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +00001018 Attribute attributeDefinition = attributes.getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001019 if (attributeDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001020 throw new IllegalStateException(getRule().getLocation() + ": " + getRuleClassNameForLogging()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001021 + " attribute " + attributeName + " is not defined");
1022 }
Michael Staiba751f922017-02-14 15:50:04 +00001023 if (attributeDefinition.getType().getLabelClass() != LabelClass.DEPENDENCY) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001024 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001025 + " is not a label type attribute");
1026 }
gregcef2c1e832017-09-12 23:10:38 +02001027 Attribute.Transition transition = attributeDefinition.getConfigurationTransition();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001028 if (mode == Mode.HOST) {
gregcef2c1e832017-09-12 23:10:38 +02001029 if (!(transition instanceof PatchTransition) && transition != ConfigurationTransition.HOST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001030 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001031 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001032 + " is not configured for the host configuration");
1033 }
1034 } else if (mode == Mode.TARGET) {
gregcef2c1e832017-09-12 23:10:38 +02001035 if (!(transition instanceof PatchTransition) && transition != ConfigurationTransition.NONE) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001036 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001037 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001038 + " is not configured for the target configuration");
1039 }
1040 } else if (mode == Mode.DATA) {
gregcef2c1e832017-09-12 23:10:38 +02001041 if (!(transition instanceof PatchTransition) && transition != ConfigurationTransition.DATA) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001042 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001043 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001044 + " is not configured for the data configuration");
1045 }
1046 } else if (mode == Mode.SPLIT) {
Chris Parsons2e62c0d2016-04-19 22:13:59 +00001047 if (!(attributeDefinition.hasSplitConfigurationTransition())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001048 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001049 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001050 + " is not configured for a split transition");
1051 }
1052 }
1053 }
1054
1055 /**
1056 * Returns the Mode for which the attribute is configured.
1057 * This is intended for Skylark, where the Mode is implicitly chosen.
1058 */
1059 public Mode getAttributeMode(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +00001060 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001061 if (attributeDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001062 throw new IllegalStateException(getRule().getLocation() + ": " + getRuleClassNameForLogging()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001063 + " attribute " + attributeName + " is not defined");
1064 }
Michael Staiba751f922017-02-14 15:50:04 +00001065 if (attributeDefinition.getType().getLabelClass() != LabelClass.DEPENDENCY) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001066 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001067 + " is not a label type attribute");
1068 }
1069 if (attributeDefinition.getConfigurationTransition() == ConfigurationTransition.HOST) {
1070 return Mode.HOST;
1071 } else if (attributeDefinition.getConfigurationTransition() == ConfigurationTransition.NONE) {
1072 return Mode.TARGET;
1073 } else if (attributeDefinition.getConfigurationTransition() == ConfigurationTransition.DATA) {
1074 return Mode.DATA;
Chris Parsons2e62c0d2016-04-19 22:13:59 +00001075 } else if (attributeDefinition.hasSplitConfigurationTransition()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001076 return Mode.SPLIT;
1077 }
1078 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001079 + getRuleClassNameForLogging() + " attribute " + attributeName + " is not configured");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001080 }
1081
1082 /**
1083 * For the specified attribute "attributeName" (which must be of type
1084 * list(label)), resolve all the labels into ConfiguredTargets (for the
1085 * configuration appropriate to the attribute) and return their build
1086 * artifacts as a {@link PrerequisiteArtifacts} instance.
1087 *
1088 * @param attributeName the name of the attribute to traverse
1089 */
1090 public PrerequisiteArtifacts getPrerequisiteArtifacts(String attributeName, Mode mode) {
1091 return PrerequisiteArtifacts.get(this, attributeName, mode);
1092 }
1093
1094 /**
1095 * For the specified attribute "attributeName" (which must be of type label),
1096 * resolves the ConfiguredTarget and returns its single build artifact.
1097 *
1098 * <p>If the attribute is optional, has no default and was not specified, then
1099 * null will be returned. Note also that null is returned (and an attribute
1100 * error is raised) if there wasn't exactly one build artifact for the target.
1101 */
1102 public Artifact getPrerequisiteArtifact(String attributeName, Mode mode) {
1103 TransitiveInfoCollection target = getPrerequisite(attributeName, mode);
1104 return transitiveInfoCollectionToArtifact(attributeName, target);
1105 }
1106
1107 /**
1108 * Equivalent to getPrerequisiteArtifact(), but also asserts that
1109 * host-configuration is appropriate for the specified attribute.
1110 */
1111 public Artifact getHostPrerequisiteArtifact(String attributeName) {
1112 TransitiveInfoCollection target = getPrerequisite(attributeName, Mode.HOST);
1113 return transitiveInfoCollectionToArtifact(attributeName, target);
1114 }
1115
1116 private Artifact transitiveInfoCollectionToArtifact(
1117 String attributeName, TransitiveInfoCollection target) {
1118 if (target != null) {
1119 Iterable<Artifact> artifacts = target.getProvider(FileProvider.class).getFilesToBuild();
1120 if (Iterables.size(artifacts) == 1) {
1121 return Iterables.getOnlyElement(artifacts);
1122 } else {
1123 attributeError(attributeName, target.getLabel() + " expected a single artifact");
1124 }
1125 }
1126 return null;
1127 }
1128
1129 /**
1130 * Returns the sole file in the "srcs" attribute. Reports an error and
1131 * (possibly) returns null if "srcs" does not identify a single file of the
1132 * expected type.
1133 */
1134 public Artifact getSingleSource(String fileTypeName) {
1135 List<Artifact> srcs = PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list();
1136 switch (srcs.size()) {
1137 case 0 : // error already issued by getSrc()
1138 return null;
1139 case 1 : // ok
1140 return Iterables.getOnlyElement(srcs);
1141 default :
1142 attributeError("srcs", "only a single " + fileTypeName + " is allowed here");
1143 return srcs.get(0);
1144 }
1145 }
1146
1147 public Artifact getSingleSource() {
Michael Staib8824d5e2016-01-20 21:37:05 +00001148 return getSingleSource(getRuleClassNameForLogging() + " source file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001149 }
1150
1151 /**
1152 * Returns a path fragment qualified by the rule name and unique fragment to
1153 * disambiguate artifacts produced from the source file appearing in
1154 * multiple rules.
1155 *
1156 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1157 */
1158 public final PathFragment getUniqueDirectory(String fragment) {
nharmata5e924af2017-05-02 18:16:23 +02001159 return getUniqueDirectory(PathFragment.create(fragment));
1160 }
1161
1162 /**
1163 * Returns a path fragment qualified by the rule name and unique fragment to
1164 * disambiguate artifacts produced from the source file appearing in
1165 * multiple rules.
1166 *
1167 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1168 */
1169 public final PathFragment getUniqueDirectory(PathFragment fragment) {
1170 return AnalysisUtils.getUniqueDirectory(getLabel(), fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001171 }
1172
1173 /**
1174 * Check that all targets that were specified as sources are from the same
1175 * package as this rule. Output a warning or an error for every target that is
1176 * imported from a different package.
1177 */
1178 public void checkSrcsSamePackage(boolean onlyWarn) {
1179 PathFragment packageName = getLabel().getPackageFragment();
1180 for (Artifact srcItem : PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list()) {
1181 if (!srcItem.isSourceArtifact()) {
1182 // In theory, we should not do this check. However, in practice, we
1183 // have a couple of rules that do not obey the "srcs must contain
1184 // files and only files" rule. Thus, we are stuck with this hack here :(
1185 continue;
1186 }
1187 Label associatedLabel = srcItem.getOwner();
1188 PathFragment itemPackageName = associatedLabel.getPackageFragment();
1189 if (!itemPackageName.equals(packageName)) {
1190 String message = "please do not import '" + associatedLabel + "' directly. "
1191 + "You should either move the file to this package or depend on "
1192 + "an appropriate rule there";
1193 if (onlyWarn) {
1194 attributeWarning("srcs", message);
1195 } else {
1196 attributeError("srcs", message);
1197 }
1198 }
1199 }
1200 }
1201
1202
1203 /**
1204 * Returns the label to which the {@code NODEP_LABEL} attribute
1205 * {@code attrName} refers, checking that it is a valid label, and that it is
1206 * referring to a local target. Reports a warning otherwise.
1207 */
1208 public Label getLocalNodepLabelAttribute(String attrName) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001209 Label label = attributes().get(attrName, BuildType.NODEP_LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001210 if (label == null) {
1211 return null;
1212 }
1213
1214 if (!getTarget().getLabel().getPackageFragment().equals(label.getPackageFragment())) {
1215 attributeWarning(attrName, "does not reference a local rule");
1216 }
1217
1218 return label;
1219 }
1220
1221 /**
1222 * Returns the implicit output artifact for a given template function. If multiple or no artifacts
1223 * can be found as a result of the template, an exception is thrown.
1224 */
Florian Weikert4b67d4f2015-09-14 13:35:34 +00001225 public Artifact getImplicitOutputArtifact(ImplicitOutputsFunction function)
1226 throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001227 Iterable<String> result;
1228 try {
1229 result = function.getImplicitOutputs(RawAttributeMapper.of(rule));
1230 } catch (EvalException e) {
1231 // It's ok as long as we don't use this method from Skylark.
1232 throw new IllegalStateException(e);
1233 }
1234 return getImplicitOutputArtifact(Iterables.getOnlyElement(result));
1235 }
1236
1237 /**
1238 * Only use from Skylark. Returns the implicit output artifact for a given output path.
1239 */
1240 public Artifact getImplicitOutputArtifact(String path) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +00001241 return getPackageRelativeArtifact(path, getBinOrGenfilesDirectory());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001242 }
1243
1244 /**
1245 * Convenience method to return a host configured target for the "compiler"
1246 * attribute. Allows caller to decide whether a warning should be printed if
1247 * the "compiler" attribute is not set to the default value.
1248 *
1249 * @param warnIfNotDefault if true, print a warning if the value for the
1250 * "compiler" attribute is set to something other than the default
1251 * @return a ConfiguredTarget using the host configuration for the "compiler"
1252 * attribute
1253 */
1254 public final FilesToRunProvider getCompiler(boolean warnIfNotDefault) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001255 Label label = attributes().get("compiler", BuildType.LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001256 if (warnIfNotDefault && !label.equals(getRule().getAttrDefaultValue("compiler"))) {
1257 attributeWarning("compiler", "setting the compiler is strongly discouraged");
1258 }
1259 return getExecutablePrerequisite("compiler", Mode.HOST);
1260 }
1261
1262 /**
1263 * Returns the (unmodifiable, ordered) list of artifacts which are the outputs
1264 * of this target.
1265 *
1266 * <p>Each element in this list is associated with a single output, either
1267 * declared implicitly (via setImplicitOutputsFunction()) or explicitly
1268 * (listed in the 'outs' attribute of our rule).
1269 */
1270 public final ImmutableList<Artifact> getOutputArtifacts() {
1271 ImmutableList.Builder<Artifact> artifacts = ImmutableList.builder();
1272 for (OutputFile out : getRule().getOutputFiles()) {
1273 artifacts.add(createOutputArtifact(out));
1274 }
1275 return artifacts.build();
1276 }
1277
1278 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001279 * Like {@link #getOutputArtifacts()} but for a singular output item.
1280 * Reports an error if the "out" attribute is not a singleton.
1281 *
1282 * @return null if the output list is empty, the artifact for the first item
1283 * of the output list otherwise
1284 */
1285 public Artifact getOutputArtifact() {
1286 List<Artifact> outs = getOutputArtifacts();
1287 if (outs.size() != 1) {
1288 attributeError("out", "exactly one output file required");
1289 if (outs.isEmpty()) {
1290 return null;
1291 }
1292 }
1293 return outs.get(0);
1294 }
1295
1296 /**
1297 * Returns an artifact with a given file extension. All other path components
1298 * are the same as in {@code pathFragment}.
1299 */
1300 public final Artifact getRelatedArtifact(PathFragment pathFragment, String extension) {
1301 PathFragment file = FileSystemUtils.replaceExtension(pathFragment, extension);
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +00001302 return getDerivedArtifact(file, getConfiguration().getBinDirectory(rule.getRepository()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001303 }
1304
1305 /**
Googlerf812a2f2016-06-13 16:14:10 +00001306 * Returns true if the target for this context is a test target.
1307 */
1308 public boolean isTestTarget() {
1309 return TargetUtils.isTestRule(getTarget());
1310 }
1311
1312 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001313 * @return true if {@code rule} is visible from {@code prerequisite}.
1314 *
1315 * <p>This only computes the logic as implemented by the visibility system. The final decision
1316 * whether a dependency is allowed is made by
1317 * {@link ConfiguredRuleClassProvider.PrerequisiteValidator}.
1318 */
1319 public static boolean isVisible(Rule rule, TransitiveInfoCollection prerequisite) {
1320 // Check visibility attribute
1321 for (PackageSpecification specification :
1322 prerequisite.getProvider(VisibilityProvider.class).getVisibility()) {
Lukacs Berki485eb962016-01-13 10:47:29 +00001323 if (specification.containsPackage(rule.getLabel().getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001324 return true;
1325 }
1326 }
1327
1328 return false;
1329 }
1330
1331 /**
1332 * @return the set of features applicable for the current rule's package.
1333 */
1334 public ImmutableSet<String> getFeatures() {
1335 return features;
1336 }
1337
Florian Weikertb8a6a942015-09-25 12:36:08 +00001338 @Override
1339 public String toString() {
1340 return "RuleContext(" + getLabel() + ", " + getConfiguration() + ")";
1341 }
1342
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001343 /**
1344 * Builder class for a RuleContext.
1345 */
Florian Weikertb8a6a942015-09-25 12:36:08 +00001346 public static final class Builder implements RuleErrorConsumer {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001347 private final AnalysisEnvironment env;
1348 private final Rule rule;
Michael Staibb51251e2015-09-29 23:31:51 +00001349 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
Greg Estrenc5a352f2015-11-13 17:25:36 +00001350 private Class<? extends BuildConfiguration.Fragment> universalFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001351 private final BuildConfiguration configuration;
Greg Estren9eb1cf02015-06-26 22:18:35 +00001352 private final BuildConfiguration hostConfiguration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001353 private final PrerequisiteValidator prerequisiteValidator;
Florian Weikertb8a6a942015-09-25 12:36:08 +00001354 private final ErrorReporter reporter;
Greg Estrend5353252016-08-11 22:13:31 +00001355 private OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap;
Lukacs Berki7894c182016-05-10 12:07:01 +00001356 private ImmutableMap<Label, ConfigMatchingProvider> configConditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001357 private NestedSet<PackageSpecification> visibility;
Dmitry Lomovace678e2015-12-16 15:10:20 +00001358 private ImmutableMap<String, Attribute> aspectAttributes;
Dmitry Lomov15756522016-12-16 16:52:37 +00001359 private ImmutableList<AspectDescriptor> aspectDescriptors;
John Cater13263f72017-05-24 19:06:47 +02001360 private ToolchainContext toolchainContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001361
Michael Staib8824d5e2016-01-20 21:37:05 +00001362 Builder(
1363 AnalysisEnvironment env,
1364 Rule rule,
Dmitry Lomov15756522016-12-16 16:52:37 +00001365 ImmutableList<AspectDescriptor> aspectDescriptors,
Michael Staib8824d5e2016-01-20 21:37:05 +00001366 BuildConfiguration configuration,
Greg Estren9eb1cf02015-06-26 22:18:35 +00001367 BuildConfiguration hostConfiguration,
Michael Staib8824d5e2016-01-20 21:37:05 +00001368 PrerequisiteValidator prerequisiteValidator,
1369 ConfigurationFragmentPolicy configurationFragmentPolicy) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001370 this.env = Preconditions.checkNotNull(env);
1371 this.rule = Preconditions.checkNotNull(rule);
Dmitry Lomov15756522016-12-16 16:52:37 +00001372 this.aspectDescriptors = aspectDescriptors;
Michael Staib8824d5e2016-01-20 21:37:05 +00001373 this.configurationFragmentPolicy = Preconditions.checkNotNull(configurationFragmentPolicy);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001374 this.configuration = Preconditions.checkNotNull(configuration);
Greg Estren9eb1cf02015-06-26 22:18:35 +00001375 this.hostConfiguration = Preconditions.checkNotNull(hostConfiguration);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001376 this.prerequisiteValidator = prerequisiteValidator;
Michael Staib8824d5e2016-01-20 21:37:05 +00001377 reporter = new ErrorReporter(env, rule, getRuleClassNameForLogging());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001378 }
1379
1380 RuleContext build() {
1381 Preconditions.checkNotNull(prerequisiteMap);
1382 Preconditions.checkNotNull(configConditions);
1383 Preconditions.checkNotNull(visibility);
Nathan Harmatafcb17112016-04-13 16:56:58 +00001384 AttributeMap attributes = ConfiguredAttributeMapper.of(rule, configConditions);
1385 validateAttributes(attributes);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001386 ListMultimap<String, ConfiguredTarget> targetMap = createTargetMap();
1387 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap =
1388 createFilesetEntryMap(rule, configConditions);
Michael Staib8824d5e2016-01-20 21:37:05 +00001389 return new RuleContext(
1390 this,
Nathan Harmatafcb17112016-04-13 16:56:58 +00001391 attributes,
Michael Staib8824d5e2016-01-20 21:37:05 +00001392 targetMap,
1393 filesetEntryMap,
1394 configConditions,
1395 universalFragment,
1396 getRuleClassNameForLogging(),
John Cater13263f72017-05-24 19:06:47 +02001397 aspectAttributes != null ? aspectAttributes : ImmutableMap.<String, Attribute>of(),
1398 toolchainContext);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001399 }
1400
Nathan Harmatafcb17112016-04-13 16:56:58 +00001401 private void validateAttributes(AttributeMap attributes) {
1402 rule.getRuleClassObject().checkAttributesNonEmpty(rule, reporter, attributes);
1403 }
1404
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001405 Builder setVisibility(NestedSet<PackageSpecification> visibility) {
1406 this.visibility = visibility;
1407 return this;
1408 }
1409
1410 /**
1411 * Sets the prerequisites and checks their visibility. It also generates appropriate error or
1412 * warning messages and sets the error flag as appropriate.
1413 */
Greg Estrend5353252016-08-11 22:13:31 +00001414 Builder setPrerequisites(OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001415 this.prerequisiteMap = Preconditions.checkNotNull(prerequisiteMap);
1416 return this;
1417 }
1418
1419 /**
Carmi Grushko06f65f72015-11-02 22:42:24 +00001420 * Adds attributes which are defined by an Aspect (and not by RuleClass).
1421 */
1422 Builder setAspectAttributes(Map<String, Attribute> aspectAttributes) {
Dmitry Lomovace678e2015-12-16 15:10:20 +00001423 this.aspectAttributes = ImmutableMap.copyOf(aspectAttributes);
Carmi Grushko06f65f72015-11-02 22:42:24 +00001424 return this;
1425 }
1426
1427 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001428 * Sets the configuration conditions needed to determine which paths to follow for this
1429 * rule's configurable attributes.
1430 */
Lukacs Berki7894c182016-05-10 12:07:01 +00001431 Builder setConfigConditions(ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001432 this.configConditions = Preconditions.checkNotNull(configConditions);
1433 return this;
1434 }
1435
Greg Estrenc5a352f2015-11-13 17:25:36 +00001436 /**
1437 * Sets the fragment that can be legally accessed even when not explicitly declared.
1438 */
1439 Builder setUniversalFragment(Class<? extends BuildConfiguration.Fragment> fragment) {
1440 // TODO(bazel-team): Add this directly to ConfigurationFragmentPolicy, so we
1441 // don't need separate logic specifically for checking this fragment. The challenge is
1442 // that we need RuleClassProvider to figure out what this fragment is, and not every
1443 // call state that creates ConfigurationFragmentPolicy has access to that.
1444 this.universalFragment = fragment;
1445 return this;
1446 }
1447
Cal Peyserf296e872016-05-03 17:36:54 +00001448 /**
1449 * Sets a map that indicates which providers should be exported to skylark under the key
1450 * (map key). These provider types will also be exportable by skylark rules under (map key).
1451 */
1452 Builder setSkylarkProvidersRegistry(
1453 ImmutableBiMap<String, Class<? extends TransitiveInfoProvider>> skylarkProviderRegistry) {
Cal Peyserf296e872016-05-03 17:36:54 +00001454 return this;
1455 }
1456
John Cater13263f72017-05-24 19:06:47 +02001457 /** Sets the {@link ToolchainContext} used to access toolchains used by this rule. */
1458 Builder setToolchainContext(ToolchainContext toolchainContext) {
1459 this.toolchainContext = toolchainContext;
1460 return this;
1461 }
1462
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001463 private boolean validateFilesetEntry(FilesetEntry filesetEntry, ConfiguredTarget src) {
1464 if (src.getProvider(FilesetProvider.class) != null) {
1465 return true;
1466 }
1467 if (filesetEntry.isSourceFileset()) {
1468 return true;
1469 }
1470
1471 Target srcTarget = src.getTarget();
1472 if (!(srcTarget instanceof FileTarget)) {
1473 attributeError("entries", String.format(
1474 "Invalid 'srcdir' target '%s'. Must be another Fileset or package",
1475 srcTarget.getLabel()));
1476 return false;
1477 }
1478
1479 if (srcTarget instanceof OutputFile) {
1480 attributeWarning("entries", String.format("'srcdir' target '%s' is not an input file. "
1481 + "This forces the Fileset to be executed unconditionally",
1482 srcTarget.getLabel()));
1483 }
1484
1485 return true;
1486 }
1487
1488 /**
1489 * Determines and returns a map from attribute name to list of configured fileset entries, based
1490 * on a PrerequisiteMap instance.
1491 */
1492 private ListMultimap<String, ConfiguredFilesetEntry> createFilesetEntryMap(
Lukacs Berki7894c182016-05-10 12:07:01 +00001493 final Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001494 final ImmutableSortedKeyListMultimap.Builder<String, ConfiguredFilesetEntry> mapBuilder =
1495 ImmutableSortedKeyListMultimap.builder();
1496 for (Attribute attr : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001497 if (attr.getType() != BuildType.FILESET_ENTRY_LIST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001498 continue;
1499 }
1500 String attributeName = attr.getName();
1501 Map<Label, ConfiguredTarget> ctMap = new HashMap<>();
1502 for (ConfiguredTarget prerequisite : prerequisiteMap.get(attr)) {
Lukacs Berki8d41ca32016-08-26 08:50:48 +00001503 ctMap.put(AliasProvider.getDependencyLabel(prerequisite), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001504 }
1505 List<FilesetEntry> entries = ConfiguredAttributeMapper.of(rule, configConditions)
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001506 .get(attributeName, BuildType.FILESET_ENTRY_LIST);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001507 for (FilesetEntry entry : entries) {
1508 if (entry.getFiles() == null) {
1509 Label label = entry.getSrcLabel();
1510 ConfiguredTarget src = ctMap.get(label);
1511 if (!validateFilesetEntry(entry, src)) {
1512 continue;
1513 }
1514
1515 mapBuilder.put(attributeName, new ConfiguredFilesetEntry(entry, src));
1516 } else {
1517 ImmutableList.Builder<TransitiveInfoCollection> files = ImmutableList.builder();
1518 for (Label file : entry.getFiles()) {
1519 files.add(ctMap.get(file));
1520 }
1521 mapBuilder.put(attributeName, new ConfiguredFilesetEntry(entry, files.build()));
1522 }
1523 }
1524 }
1525 return mapBuilder.build();
1526 }
1527
1528 /**
1529 * Determines and returns a map from attribute name to list of configured targets.
1530 */
1531 private ImmutableSortedKeyListMultimap<String, ConfiguredTarget> createTargetMap() {
1532 ImmutableSortedKeyListMultimap.Builder<String, ConfiguredTarget> mapBuilder =
1533 ImmutableSortedKeyListMultimap.builder();
1534
1535 for (Map.Entry<Attribute, Collection<ConfiguredTarget>> entry :
1536 prerequisiteMap.asMap().entrySet()) {
1537 Attribute attribute = entry.getKey();
1538 if (attribute == null) {
1539 continue;
1540 }
lberki1cd6d1e2017-06-14 16:20:19 +02001541
1542 if (attribute.isSingleArtifact() && entry.getValue().size() > 1) {
1543 attributeError(attribute.getName(), "must contain a single dependency");
1544 continue;
1545 }
1546
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001547 if (attribute.isSilentRuleClassFilter()) {
1548 Predicate<RuleClass> filter = attribute.getAllowedRuleClassesPredicate();
1549 for (ConfiguredTarget configuredTarget : entry.getValue()) {
1550 Target prerequisiteTarget = configuredTarget.getTarget();
1551 if ((prerequisiteTarget instanceof Rule)
1552 && filter.apply(((Rule) prerequisiteTarget).getRuleClassObject())) {
1553 validateDirectPrerequisite(attribute, configuredTarget);
1554 mapBuilder.put(attribute.getName(), configuredTarget);
1555 }
1556 }
1557 } else {
1558 for (ConfiguredTarget configuredTarget : entry.getValue()) {
1559 validateDirectPrerequisite(attribute, configuredTarget);
1560 mapBuilder.put(attribute.getName(), configuredTarget);
1561 }
1562 }
1563 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001564 return mapBuilder.build();
1565 }
1566
Klaus Aehlig16a107d2017-05-31 18:02:43 +02001567 public void post(Postable event) {
1568 reporter.post(event);
1569 }
1570
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001571 public void reportError(Location location, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001572 reporter.reportError(location, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001573 }
1574
Florian Weikertb8a6a942015-09-25 12:36:08 +00001575 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001576 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001577 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001578 }
1579
Florian Weikertb8a6a942015-09-25 12:36:08 +00001580 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001581 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001582 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001583 }
1584
1585 public void reportWarning(Location location, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001586 reporter.reportWarning(location, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001587 }
1588
Florian Weikertb8a6a942015-09-25 12:36:08 +00001589 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001590 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001591 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001592 }
1593
Florian Weikertb8a6a942015-09-25 12:36:08 +00001594 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001595 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001596 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001597 }
1598
Googlere49cd592016-07-29 19:32:38 +00001599 private String badPrerequisiteMessage(String targetKind, ConfiguredTarget prerequisite,
1600 String reason, boolean isWarning) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001601 String msgPrefix = targetKind != null ? targetKind + " " : "";
1602 String msgReason = reason != null ? " (" + reason + ")" : "";
1603 if (isWarning) {
Googlere49cd592016-07-29 19:32:38 +00001604 return String.format(
Lukacs Berkic10120a2016-12-06 15:56:14 +00001605 "%s%s is unexpected here%s; continuing anyway",
1606 msgPrefix, AliasProvider.printLabelWithAliasChain(prerequisite),
Googlere49cd592016-07-29 19:32:38 +00001607 msgReason);
1608 }
Lukacs Berkic10120a2016-12-06 15:56:14 +00001609 return String.format("%s%s is misplaced here%s",
1610 msgPrefix, AliasProvider.printLabelWithAliasChain(prerequisite), msgReason);
Googlere49cd592016-07-29 19:32:38 +00001611 }
1612
1613 private void reportBadPrerequisite(Attribute attribute, String targetKind,
1614 ConfiguredTarget prerequisite, String reason, boolean isWarning) {
1615 String message = badPrerequisiteMessage(targetKind, prerequisite, reason, isWarning);
1616 if (isWarning) {
1617 attributeWarning(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001618 } else {
Googlere49cd592016-07-29 19:32:38 +00001619 attributeError(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001620 }
1621 }
1622
1623 private void validateDirectPrerequisiteType(ConfiguredTarget prerequisite,
1624 Attribute attribute) {
1625 Target prerequisiteTarget = prerequisite.getTarget();
1626 Label prerequisiteLabel = prerequisiteTarget.getLabel();
1627
1628 if (prerequisiteTarget instanceof Rule) {
1629 Rule prerequisiteRule = (Rule) prerequisiteTarget;
1630
1631 String reason = attribute.getValidityPredicate().checkValid(rule, prerequisiteRule);
1632 if (reason != null) {
1633 reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(),
Lukacs Berki7894c182016-05-10 12:07:01 +00001634 prerequisite, reason, false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001635 }
1636 }
1637
Yun Pengefd7ca12016-03-03 13:14:38 +00001638 if (prerequisiteTarget instanceof Rule) {
1639 validateRuleDependency(prerequisite, attribute);
1640 } else if (prerequisiteTarget instanceof FileTarget) {
1641 if (attribute.isStrictLabelCheckingEnabled()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001642 if (!attribute.getAllowedFileTypesPredicate()
1643 .apply(((FileTarget) prerequisiteTarget).getFilename())) {
1644 if (prerequisiteTarget instanceof InputFile
1645 && !((InputFile) prerequisiteTarget).getPath().exists()) {
1646 // Misplaced labels, no corresponding target exists
1647 if (attribute.getAllowedFileTypesPredicate().isNone()
1648 && !((InputFile) prerequisiteTarget).getFilename().contains(".")) {
1649 // There are no allowed files in the attribute but it's not a valid rule,
1650 // and the filename doesn't contain a dot --> probably a misspelled rule
1651 attributeError(attribute.getName(),
1652 "rule '" + prerequisiteLabel + "' does not exist");
1653 } else {
1654 attributeError(attribute.getName(),
1655 "target '" + prerequisiteLabel + "' does not exist");
1656 }
1657 } else {
1658 // The file exists but has a bad extension
Lukacs Berki7894c182016-05-10 12:07:01 +00001659 reportBadPrerequisite(attribute, "file", prerequisite,
Ulf Adams07dba942015-03-05 14:47:37 +00001660 "expected " + attribute.getAllowedFileTypesPredicate(), false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001661 }
1662 }
1663 }
1664 }
1665 }
1666
Michael Staib2707a882016-09-16 21:06:40 +00001667 /** Returns whether the context being constructed is for the evaluation of an aspect. */
1668 public boolean forAspect() {
Dmitry Lomov15756522016-12-16 16:52:37 +00001669 return !aspectDescriptors.isEmpty();
Michael Staib2707a882016-09-16 21:06:40 +00001670 }
1671
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001672 public Rule getRule() {
1673 return rule;
1674 }
1675
Michael Staib8824d5e2016-01-20 21:37:05 +00001676 /**
1677 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
1678 */
1679 public String getRuleClassNameForLogging() {
Dmitry Lomov15756522016-12-16 16:52:37 +00001680 if (aspectDescriptors.isEmpty()) {
1681 return rule.getRuleClass();
1682 }
1683
1684 return Joiner.on(",").join(aspectDescriptors) + " aspect on " + rule.getRuleClass();
Michael Staib8824d5e2016-01-20 21:37:05 +00001685 }
1686
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001687 public BuildConfiguration getConfiguration() {
1688 return configuration;
1689 }
1690
1691 /**
1692 * @return true if {@code rule} is visible from {@code prerequisite}.
1693 *
1694 * <p>This only computes the logic as implemented by the visibility system. The final decision
1695 * whether a dependency is allowed is made by
1696 * {@link ConfiguredRuleClassProvider.PrerequisiteValidator}, who is supposed to call this
1697 * method to determine whether a dependency is allowed as per visibility rules.
1698 */
1699 public boolean isVisible(TransitiveInfoCollection prerequisite) {
1700 return RuleContext.isVisible(rule, prerequisite);
1701 }
1702
1703 private void validateDirectPrerequisiteFileTypes(ConfiguredTarget prerequisite,
1704 Attribute attribute) {
1705 if (attribute.isSkipAnalysisTimeFileTypeCheck()) {
1706 return;
1707 }
1708 FileTypeSet allowedFileTypes = attribute.getAllowedFileTypesPredicate();
Ulf Adams788fd1a2015-03-12 13:54:09 +00001709 if (allowedFileTypes == null) {
1710 // It's not a label or label_list attribute.
1711 return;
1712 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001713 if (allowedFileTypes == FileTypeSet.ANY_FILE && !attribute.isNonEmpty()
1714 && !attribute.isSingleArtifact()) {
1715 return;
1716 }
1717
1718 // If we allow any file we still need to check if there are actually files generated
1719 // Note that this check only runs for ANY_FILE predicates if the attribute is NON_EMPTY
1720 // or SINGLE_ARTIFACT
1721 // If we performed this check when allowedFileTypes == NO_FILE this would
1722 // always throw an error in those cases
1723 if (allowedFileTypes != FileTypeSet.NO_FILE) {
1724 Iterable<Artifact> artifacts = prerequisite.getProvider(FileProvider.class)
1725 .getFilesToBuild();
1726 if (attribute.isSingleArtifact() && Iterables.size(artifacts) != 1) {
1727 attributeError(attribute.getName(),
1728 "'" + prerequisite.getLabel() + "' must produce a single file");
1729 return;
1730 }
1731 for (Artifact sourceArtifact : artifacts) {
1732 if (allowedFileTypes.apply(sourceArtifact.getFilename())) {
1733 return;
1734 }
1735 }
1736 attributeError(attribute.getName(), "'" + prerequisite.getLabel()
Michael Staib8824d5e2016-01-20 21:37:05 +00001737 + "' does not produce any " + getRuleClassNameForLogging() + " " + attribute.getName()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001738 + " files (expected " + allowedFileTypes + ")");
1739 }
1740 }
1741
dslomov7df85152017-08-01 20:47:59 +02001742 /**
dslomovc13bb392017-08-02 23:29:54 +02001743 * Because some rules still have to use allowedRuleClasses to do rule dependency validation. A
1744 * dependency is valid if it is from a rule in allowedRuledClasses, OR if all of the providers
1745 * in requiredProviders are provided by the target.
dslomov7df85152017-08-01 20:47:59 +02001746 */
1747 private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) {
dslomov7df85152017-08-01 20:47:59 +02001748
dslomovc13bb392017-08-02 23:29:54 +02001749 Set<String> unfulfilledRequirements = new LinkedHashSet<>();
1750 if (checkRuleDependencyClass(prerequisite, attribute, unfulfilledRequirements)) {
1751 return;
1752 }
1753
1754 if (checkRuleDependencyClassWarnings(prerequisite, attribute)) {
1755 return;
1756 }
1757
1758 if (checkRuleDependencyMandatoryProviders(prerequisite, attribute, unfulfilledRequirements)) {
1759 return;
1760 }
1761
1762 // not allowed rule class and some mandatory providers missing => reject.
1763 if (!unfulfilledRequirements.isEmpty()) {
1764 attributeError(
1765 attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
1766 }
1767 }
1768
1769 /** Check if prerequisite should be allowed based on its rule class. */
1770 private boolean checkRuleDependencyClass(
1771 ConfiguredTarget prerequisite, Attribute attribute, Set<String> unfulfilledRequirements) {
dslomovc32e1b12017-07-31 19:23:52 +02001772 if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
dslomovc13bb392017-08-02 23:29:54 +02001773 if (attribute
1774 .getAllowedRuleClassesPredicate()
1775 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02001776 // prerequisite has an allowed rule class => accept.
dslomovc13bb392017-08-02 23:29:54 +02001777 return true;
dslomovc32e1b12017-07-31 19:23:52 +02001778 }
1779 // remember that the rule class that was not allowed;
1780 // but maybe prerequisite provides required providers? do not reject yet.
dslomovc13bb392017-08-02 23:29:54 +02001781 unfulfilledRequirements.add(
dslomovc32e1b12017-07-31 19:23:52 +02001782 badPrerequisiteMessage(
dslomovc13bb392017-08-02 23:29:54 +02001783 prerequisite.getTarget().getTargetKind(),
dslomovc32e1b12017-07-31 19:23:52 +02001784 prerequisite,
1785 "expected " + attribute.getAllowedRuleClassesPredicate(),
dslomovc13bb392017-08-02 23:29:54 +02001786 false));
dslomovc32e1b12017-07-31 19:23:52 +02001787 }
dslomovc13bb392017-08-02 23:29:54 +02001788 return false;
1789 }
dslomovc32e1b12017-07-31 19:23:52 +02001790
dslomovc13bb392017-08-02 23:29:54 +02001791 /**
1792 * Check if prerequisite should be allowed with warning based on its rule class.
1793 *
1794 * <p>If yes, also issues said warning.
1795 */
1796 private boolean checkRuleDependencyClassWarnings(
1797 ConfiguredTarget prerequisite, Attribute attribute) {
1798 if (attribute
1799 .getAllowedRuleClassesWarningPredicate()
1800 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02001801 Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate();
dslomovc13bb392017-08-02 23:29:54 +02001802 reportBadPrerequisite(
1803 attribute,
1804 prerequisite.getTarget().getTargetKind(),
1805 prerequisite,
dslomovc32e1b12017-07-31 19:23:52 +02001806 allowedRuleClasses == Predicates.<RuleClass>alwaysTrue()
dslomovde965ac2017-07-31 21:07:51 +02001807 ? null
1808 : "expected " + allowedRuleClasses,
dslomovc32e1b12017-07-31 19:23:52 +02001809 true);
1810 // prerequisite has a rule class allowed with a warning => accept, emitting a warning.
dslomovc13bb392017-08-02 23:29:54 +02001811 return true;
1812 }
1813 return false;
1814 }
1815
1816 /** Check if prerequisite should be allowed based on required providers on the attribute. */
1817 private boolean checkRuleDependencyMandatoryProviders(
1818 ConfiguredTarget prerequisite, Attribute attribute, Set<String> unfulfilledRequirements) {
1819 RequiredProviders requiredProviders = attribute.getRequiredProviders();
1820
1821 if (requiredProviders.acceptsAny()) {
1822 // If no required providers specified, we do not know if we should accept.
1823 return false;
dslomovc32e1b12017-07-31 19:23:52 +02001824 }
1825
dslomovc13bb392017-08-02 23:29:54 +02001826 if (prerequisite.satisfies(requiredProviders)) {
1827 return true;
dslomovc32e1b12017-07-31 19:23:52 +02001828 }
1829
dslomovc13bb392017-08-02 23:29:54 +02001830 unfulfilledRequirements.add(
1831 String.format(
1832 "'%s' does not have mandatory providers: %s",
1833 prerequisite.getLabel(),
1834 prerequisite.missingProviders(requiredProviders).getDescription()));
dslomovc32e1b12017-07-31 19:23:52 +02001835
dslomovc13bb392017-08-02 23:29:54 +02001836 return false;
dslomovc32e1b12017-07-31 19:23:52 +02001837 }
1838
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001839 private void validateDirectPrerequisite(Attribute attribute, ConfiguredTarget prerequisite) {
1840 validateDirectPrerequisiteType(prerequisite, attribute);
1841 validateDirectPrerequisiteFileTypes(prerequisite, attribute);
Greg Estren875c7a72015-09-24 19:57:54 +00001842 if (attribute.performPrereqValidatorCheck()) {
Ulf Adams0b638972015-09-08 13:25:35 +00001843 prerequisiteValidator.validate(this, prerequisite, attribute);
1844 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001845 }
1846 }
1847
Florian Weikertb8a6a942015-09-25 12:36:08 +00001848 /**
1849 * Helper class for reporting errors and warnings.
1850 */
1851 public static final class ErrorReporter implements RuleErrorConsumer {
1852 private final AnalysisEnvironment env;
1853 private final Rule rule;
Michael Staib8824d5e2016-01-20 21:37:05 +00001854 private final String ruleClassNameForLogging;
Florian Weikertb8a6a942015-09-25 12:36:08 +00001855
Michael Staib8824d5e2016-01-20 21:37:05 +00001856 ErrorReporter(AnalysisEnvironment env, Rule rule, String ruleClassNameForLogging) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001857 this.env = env;
1858 this.rule = rule;
Michael Staib8824d5e2016-01-20 21:37:05 +00001859 this.ruleClassNameForLogging = ruleClassNameForLogging;
Florian Weikertb8a6a942015-09-25 12:36:08 +00001860 }
1861
1862 public void reportError(Location location, String message) {
1863 env.getEventHandler().handle(Event.error(location, message));
1864 }
1865
Klaus Aehlig16a107d2017-05-31 18:02:43 +02001866 public void post(Postable event) {
1867 env.getEventHandler().post(event);
1868 }
1869
Florian Weikertb8a6a942015-09-25 12:36:08 +00001870 @Override
1871 public void ruleError(String message) {
1872 reportError(rule.getLocation(), prefixRuleMessage(message));
1873 }
1874
1875 @Override
1876 public void attributeError(String attrName, String message) {
Florian Weikert5c679342015-11-04 16:53:59 +00001877 reportError(rule.getAttributeLocation(attrName), completeAttributeMessage(attrName, message));
Florian Weikertb8a6a942015-09-25 12:36:08 +00001878 }
1879
1880 public void reportWarning(Location location, String message) {
1881 env.getEventHandler().handle(Event.warn(location, message));
1882 }
1883
1884 @Override
1885 public void ruleWarning(String message) {
1886 env.getEventHandler().handle(Event.warn(rule.getLocation(), prefixRuleMessage(message)));
1887 }
1888
1889 @Override
1890 public void attributeWarning(String attrName, String message) {
Florian Weikert5c679342015-11-04 16:53:59 +00001891 reportWarning(
1892 rule.getAttributeLocation(attrName), completeAttributeMessage(attrName, message));
Florian Weikertb8a6a942015-09-25 12:36:08 +00001893 }
1894
1895 private String prefixRuleMessage(String message) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001896 return String.format(
1897 "in %s rule %s: %s", getRuleClassNameForLogging(), rule.getLabel(), message);
Florian Weikertb8a6a942015-09-25 12:36:08 +00001898 }
1899
1900 private String maskInternalAttributeNames(String name) {
1901 return Attribute.isImplicit(name) ? "(an implicit dependency)" : name;
1902 }
1903
1904 /**
1905 * Prefixes the given message with details about the rule and appends details about the macro
1906 * that created this rule, if applicable.
1907 */
1908 private String completeAttributeMessage(String attrName, String message) {
1909 // Appends a note to the given message if the offending rule was created by a macro.
1910 String macroMessageAppendix =
Florian Weikert5c679342015-11-04 16:53:59 +00001911 rule.wasCreatedByMacro()
Florian Weikertb8a6a942015-09-25 12:36:08 +00001912 ? String.format(
1913 ". Since this rule was created by the macro '%s', the error might have been "
1914 + "caused by the macro implementation in %s",
Florian Weikert5c679342015-11-04 16:53:59 +00001915 getGeneratorFunction(), rule.getAttributeLocationWithoutMacro(attrName))
Florian Weikertb8a6a942015-09-25 12:36:08 +00001916 : "";
1917
1918 return String.format("in %s attribute of %s rule %s: %s%s",
Michael Staib8824d5e2016-01-20 21:37:05 +00001919 maskInternalAttributeNames(attrName), getRuleClassNameForLogging(), rule.getLabel(),
1920 message, macroMessageAppendix);
1921 }
1922
1923 /**
1924 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
1925 */
1926 private String getRuleClassNameForLogging() {
1927 return ruleClassNameForLogging;
Florian Weikertb8a6a942015-09-25 12:36:08 +00001928 }
1929
Florian Weikertb8a6a942015-09-25 12:36:08 +00001930 private String getGeneratorFunction() {
1931 return (String) rule.getAttributeContainer().getAttr("generator_function");
1932 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001933 }
1934}