blob: b11ba26463b827b5b00eaa809083460bcc4f05b9 [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;
tomlua155b532017-11-08 20:12:47 +010020import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010021import com.google.common.base.Predicate;
Yun Pengefd7ca12016-03-03 13:14:38 +000022import com.google.common.base.Predicates;
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;
janakrf3e6f252018-01-18 07:45:12 -080031import com.google.common.collect.Lists;
mjhalupkade47f212018-02-12 12:31:21 -080032import com.google.common.collect.Maps;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033import com.google.common.collect.Multimaps;
34import com.google.common.collect.Sets;
35import com.google.devtools.build.lib.actions.Action;
Rumou Duan33bab462016-04-25 17:55:12 +000036import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
plf1f341a62019-04-01 14:02:14 -070037import com.google.devtools.build.lib.actions.ActionKeyContext;
janakreaff19c2019-01-31 13:59:40 -080038import com.google.devtools.build.lib.actions.ActionLookupValue;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039import com.google.devtools.build.lib.actions.ActionOwner;
40import com.google.devtools.build.lib.actions.ActionRegistry;
41import com.google.devtools.build.lib.actions.Artifact;
cpeyserac09f0a2018-02-05 09:33:15 -080042import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
tomlu1cdcdf92018-01-16 11:07:51 -080043import com.google.devtools.build.lib.actions.ArtifactRoot;
lberkiee2dcae2018-03-28 05:49:04 -070044import com.google.devtools.build.lib.analysis.AliasProvider.TargetMode;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.PrerequisiteValidator;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
Ulf Adamsc272e0f2015-04-22 19:56:21 +000047import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010048import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
49import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
Greg Estren66cadd32016-08-05 21:07:02 +000050import com.google.devtools.build.lib.analysis.config.BuildOptions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010051import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
gregcee495e6b2019-04-30 14:07:06 -070052import com.google.devtools.build.lib.analysis.config.CoreOptions;
Florian Weikert3f8aac92015-09-07 12:06:02 +000053import com.google.devtools.build.lib.analysis.config.FragmentCollection;
gregcebe55e112018-01-30 11:04:53 -080054import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
gregce7fa23ea2018-01-18 12:46:04 -080055import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
gregce6bc35ed2017-12-22 11:51:39 -080056import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
John Cater5adcd3e2019-03-28 10:14:32 -070057import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
gregce593f7f92017-09-19 02:02:21 +020058import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
gregce6acfe4e2018-05-25 08:38:39 -070059import com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics;
John Cater15c90b32017-12-18 08:34:40 -080060import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
janakreaff19c2019-01-31 13:59:40 -080061import com.google.devtools.build.lib.analysis.skylark.SymbolGenerator;
ulfjack01bf32e2017-11-02 17:50:07 -040062import com.google.devtools.build.lib.analysis.stringtemplate.TemplateContext;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000063import com.google.devtools.build.lib.cmdline.Label;
dslomovfd62e762017-09-19 16:55:53 +020064import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010065import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap;
66import com.google.devtools.build.lib.collect.nestedset.NestedSet;
67import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
Klaus Aehlig16a107d2017-05-31 18:02:43 +020068import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010069import com.google.devtools.build.lib.events.Location;
dslomov44d15712017-12-20 05:42:28 -080070import com.google.devtools.build.lib.packages.Aspect;
Dmitry Lomov15756522016-12-16 16:52:37 +000071import com.google.devtools.build.lib.packages.AspectDescriptor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010072import com.google.devtools.build.lib.packages.Attribute;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010073import com.google.devtools.build.lib.packages.AttributeMap;
John Cater2c0dece2019-04-02 09:18:18 -070074import com.google.devtools.build.lib.packages.AttributeTransitionData;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000075import com.google.devtools.build.lib.packages.BuildType;
cparsons2d67cf92018-05-24 14:02:09 -070076import com.google.devtools.build.lib.packages.BuiltinProvider;
Michael Staibb51251e2015-09-29 23:31:51 +000077import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy;
cparsons78927792017-10-11 00:14:19 +020078import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.lib.packages.FileTarget;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000080import com.google.devtools.build.lib.packages.FilesetEntry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010081import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
dslomovde965ac2017-07-31 21:07:51 +020082import com.google.devtools.build.lib.packages.Info;
cparsons4ebf6c02018-08-17 14:49:36 -070083import com.google.devtools.build.lib.packages.InfoInterface;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010084import com.google.devtools.build.lib.packages.InputFile;
dslomovde965ac2017-07-31 21:07:51 +020085import com.google.devtools.build.lib.packages.NativeProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010086import com.google.devtools.build.lib.packages.OutputFile;
cushon34ff85e2017-11-15 08:59:27 -080087import com.google.devtools.build.lib.packages.PackageSpecification.PackageGroupContents;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010088import com.google.devtools.build.lib.packages.RawAttributeMapper;
dslomovc13bb392017-08-02 23:29:54 +020089import com.google.devtools.build.lib.packages.RequiredProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090import com.google.devtools.build.lib.packages.Rule;
91import com.google.devtools.build.lib.packages.RuleClass;
92import com.google.devtools.build.lib.packages.RuleErrorConsumer;
93import com.google.devtools.build.lib.packages.Target;
94import com.google.devtools.build.lib.packages.TargetUtils;
janakr9c101402018-03-10 06:48:59 -080095import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010096import com.google.devtools.build.lib.syntax.EvalException;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000097import com.google.devtools.build.lib.syntax.Type;
Michael Staiba751f922017-02-14 15:50:04 +000098import com.google.devtools.build.lib.syntax.Type.LabelClass;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010099import com.google.devtools.build.lib.util.FileTypeSet;
cparsons0623d3c2018-10-23 16:06:30 -0700100import com.google.devtools.build.lib.util.OS;
Greg Estrend5353252016-08-11 22:13:31 +0000101import com.google.devtools.build.lib.util.OrderedSetMultimap;
Googlere49cd592016-07-29 19:32:38 +0000102import com.google.devtools.build.lib.util.StringUtil;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100103import com.google.devtools.build.lib.vfs.FileSystemUtils;
104import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100105import java.util.Collection;
106import java.util.HashMap;
107import java.util.HashSet;
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +0000108import java.util.LinkedHashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100109import java.util.List;
110import java.util.Map;
111import java.util.Set;
dslomov44d15712017-12-20 05:42:28 -0800112import java.util.stream.Collectors;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100113import javax.annotation.Nullable;
114
115/**
Lukacs Berki2300cd62016-05-19 11:06:37 +0000116 * The totality of data available during the analysis of a rule.
Janak Ramakrishnan81c5bd82016-03-22 20:07:43 +0000117 *
118 * <p>These objects should not outlast the analysis phase. Do not pass them to {@link Action}
119 * objects or other persistent objects. There are internal tests to ensure that RuleContext objects
120 * are not persisted that check the name of this class, so update those tests if you change this
121 * class's name.
Lukacs Berki2300cd62016-05-19 11:06:37 +0000122 *
ulfjack26d0e492017-08-07 13:42:33 +0200123 * @see com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100124 */
125public final class RuleContext extends TargetContext
126 implements ActionConstructionContext, ActionRegistry, RuleErrorConsumer {
Carmi Grushko33aa3062016-11-11 02:45:29 +0000127
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100128 /**
129 * The configured version of FilesetEntry.
130 */
131 @Immutable
132 public static final class ConfiguredFilesetEntry {
133 private final FilesetEntry entry;
134 private final TransitiveInfoCollection src;
135 private final ImmutableList<TransitiveInfoCollection> files;
136
137 ConfiguredFilesetEntry(FilesetEntry entry, TransitiveInfoCollection src) {
138 this.entry = entry;
139 this.src = src;
140 this.files = null;
141 }
142
143 ConfiguredFilesetEntry(FilesetEntry entry, ImmutableList<TransitiveInfoCollection> files) {
144 this.entry = entry;
145 this.src = null;
146 this.files = files;
147 }
148
149 public FilesetEntry getEntry() {
150 return entry;
151 }
152
153 public TransitiveInfoCollection getSrc() {
154 return src;
155 }
156
157 /**
158 * Targets from FilesetEntry.files, or null if the user omitted it.
159 */
160 @Nullable
Ulf Adams10993fe2016-04-19 12:55:12 +0000161 public ImmutableList<TransitiveInfoCollection> getFiles() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100162 return files;
163 }
164 }
165
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000166 private static final String HOST_CONFIGURATION_PROGRESS_TAG = "for host";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100167
168 private final Rule rule;
dslomov44d15712017-12-20 05:42:28 -0800169 /**
170 * A list of all aspects applied to the target. If this <code>RuleContext</code>
171 * is for a rule implementation, <code>aspects</code> is an empty list.
172 *
173 * Otherwise, the last aspect in <code>aspects</code> list is the aspect which
174 * this <code>RuleCointext</code> is for.
175 */
176 private final ImmutableList<Aspect> aspects;
Dmitry Lomov15756522016-12-16 16:52:37 +0000177 private final ImmutableList<AspectDescriptor> aspectDescriptors;
janakr9c101402018-03-10 06:48:59 -0800178 private final ListMultimap<String, ConfiguredTargetAndData> targetMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100179 private final ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap;
Lukacs Berki7894c182016-05-10 12:07:01 +0000180 private final ImmutableMap<Label, ConfigMatchingProvider> configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000181 private final AspectAwareAttributeMapper attributes;
Googler993f1de2018-02-20 02:31:10 -0800182 private final ImmutableSet<String> enabledFeatures;
183 private final ImmutableSet<String> disabledFeatures;
Michael Staib8824d5e2016-01-20 21:37:05 +0000184 private final String ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000185 private final BuildConfiguration hostConfiguration;
Michael Staibb51251e2015-09-29 23:31:51 +0000186 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
lberki78651d42018-04-06 01:52:58 -0700187 private final ImmutableList<Class<? extends BuildConfiguration.Fragment>> universalFragments;
cparsonse8d450c2018-10-04 16:01:53 -0700188 private final RuleErrorConsumer reporter;
John Catercdfa9ca2019-04-05 12:32:09 -0700189 @Nullable private final ResolvedToolchainContext toolchainContext;
gregce6acfe4e2018-05-25 08:38:39 -0700190 private final ConstraintSemantics constraintSemantics;
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000191
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100192 private ActionOwner actionOwner;
janakreaff19c2019-01-31 13:59:40 -0800193 private final SymbolGenerator<ActionLookupValue.ActionLookupKey> actionOwnerSymbolGenerator;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100194
195 /* lazily computed cache for Make variables, computed from the above. See get... method */
196 private transient ConfigurationMakeVariableContext configurationMakeVariableContext = null;
197
Dmitry Lomovace678e2015-12-16 15:10:20 +0000198 private RuleContext(
199 Builder builder,
Nathan Harmatafcb17112016-04-13 16:56:58 +0000200 AttributeMap attributes,
janakr9c101402018-03-10 06:48:59 -0800201 ListMultimap<String, ConfiguredTargetAndData> targetMap,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100202 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap,
Lukacs Berki7894c182016-05-10 12:07:01 +0000203 ImmutableMap<Label, ConfigMatchingProvider> configConditions,
janakreaff19c2019-01-31 13:59:40 -0800204 ImmutableList<Class<? extends Fragment>> universalFragments,
Michael Staib8824d5e2016-01-20 21:37:05 +0000205 String ruleClassNameForLogging,
janakreaff19c2019-01-31 13:59:40 -0800206 ActionLookupValue.ActionLookupKey actionLookupKey,
John Cater13263f72017-05-24 19:06:47 +0200207 ImmutableMap<String, Attribute> aspectAttributes,
John Catercdfa9ca2019-04-05 12:32:09 -0700208 @Nullable ResolvedToolchainContext toolchainContext,
gregce6acfe4e2018-05-25 08:38:39 -0700209 ConstraintSemantics constraintSemantics) {
lpino5fe7ed02018-07-18 05:55:23 -0700210 super(
211 builder.env,
212 builder.target.getAssociatedRule(),
213 builder.configuration,
214 builder.prerequisiteMap.get(null),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100215 builder.visibility);
lpino5fe7ed02018-07-18 05:55:23 -0700216 this.rule = builder.target.getAssociatedRule();
dslomov44d15712017-12-20 05:42:28 -0800217 this.aspects = builder.aspects;
218 this.aspectDescriptors =
219 builder
220 .aspects
221 .stream()
222 .map(a -> a.getDescriptor())
223 .collect(ImmutableList.toImmutableList());
Michael Staibb51251e2015-09-29 23:31:51 +0000224 this.configurationFragmentPolicy = builder.configurationFragmentPolicy;
lberki78651d42018-04-06 01:52:58 -0700225 this.universalFragments = universalFragments;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100226 this.targetMap = targetMap;
227 this.filesetEntryMap = filesetEntryMap;
228 this.configConditions = configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000229 this.attributes = new AspectAwareAttributeMapper(attributes, aspectAttributes);
Googler993f1de2018-02-20 02:31:10 -0800230 Set<String> allEnabledFeatures = new HashSet<>();
231 Set<String> allDisabledFeatures = new HashSet<>();
232 getAllFeatures(allEnabledFeatures, allDisabledFeatures);
233 this.enabledFeatures = ImmutableSortedSet.copyOf(allEnabledFeatures);
234 this.disabledFeatures = ImmutableSortedSet.copyOf(allDisabledFeatures);
Michael Staib8824d5e2016-01-20 21:37:05 +0000235 this.ruleClassNameForLogging = ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000236 this.hostConfiguration = builder.hostConfiguration;
janakreaff19c2019-01-31 13:59:40 -0800237 this.actionOwnerSymbolGenerator = new SymbolGenerator<>(actionLookupKey);
Florian Weikertb8a6a942015-09-25 12:36:08 +0000238 reporter = builder.reporter;
John Cater13263f72017-05-24 19:06:47 +0200239 this.toolchainContext = toolchainContext;
gregce6acfe4e2018-05-25 08:38:39 -0700240 this.constraintSemantics = constraintSemantics;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100241 }
242
Googler993f1de2018-02-20 02:31:10 -0800243 private void getAllFeatures(Set<String> allEnabledFeatures, Set<String> allDisabledFeatures) {
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000244 Set<String> globallyEnabled = new HashSet<>();
245 Set<String> globallyDisabled = new HashSet<>();
246 parseFeatures(getConfiguration().getDefaultFeatures(), globallyEnabled, globallyDisabled);
247 Set<String> packageEnabled = new HashSet<>();
248 Set<String> packageDisabled = new HashSet<>();
249 parseFeatures(getRule().getPackage().getFeatures(), packageEnabled, packageDisabled);
Googler8e3afcc2017-12-20 08:10:21 -0800250 Set<String> ruleEnabled = new HashSet<>();
251 Set<String> ruleDisabled = new HashSet<>();
252 if (attributes().has("features", Type.STRING_LIST)) {
253 parseFeatures(attributes().get("features", Type.STRING_LIST), ruleEnabled, ruleDisabled);
254 }
Googler993f1de2018-02-20 02:31:10 -0800255
Googler8e3afcc2017-12-20 08:10:21 -0800256 Set<String> ruleDisabledFeatures =
257 Sets.union(ruleDisabled, Sets.difference(packageDisabled, ruleEnabled));
Googler993f1de2018-02-20 02:31:10 -0800258 allDisabledFeatures.addAll(Sets.union(ruleDisabledFeatures, globallyDisabled));
Googler993f1de2018-02-20 02:31:10 -0800259
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000260 Set<String> packageFeatures =
261 Sets.difference(Sets.union(globallyEnabled, packageEnabled), packageDisabled);
Googler8e3afcc2017-12-20 08:10:21 -0800262 Set<String> ruleFeatures =
263 Sets.difference(Sets.union(packageFeatures, ruleEnabled), ruleDisabled);
Googler993f1de2018-02-20 02:31:10 -0800264 allEnabledFeatures.addAll(Sets.difference(ruleFeatures, globallyDisabled));
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000265 }
266
267 private void parseFeatures(Iterable<String> features, Set<String> enabled, Set<String> disabled) {
268 for (String feature : features) {
269 if (feature.startsWith("-")) {
270 disabled.add(feature.substring(1));
271 } else if (feature.equals("no_layering_check")) {
272 // TODO(bazel-team): Remove once we do not have BUILD files left that contain
273 // 'no_layering_check'.
274 disabled.add(feature.substring(3));
275 } else {
276 enabled.add(feature);
277 }
278 }
279 }
280
dslomovfd62e762017-09-19 16:55:53 +0200281 public RepositoryName getRepository() {
282 return rule.getRepository();
283 }
284
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100285 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800286 public ArtifactRoot getBinDirectory() {
dslomovfd62e762017-09-19 16:55:53 +0200287 return getConfiguration().getBinDirectory(rule.getRepository());
288 }
289
290 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800291 public ArtifactRoot getMiddlemanDirectory() {
dslomovfd62e762017-09-19 16:55:53 +0200292 return getConfiguration().getMiddlemanDirectory(rule.getRepository());
293 }
cparsons88821922017-10-11 01:21:46 +0200294
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100295 public Rule getRule() {
296 return rule;
297 }
298
dslomov44d15712017-12-20 05:42:28 -0800299 public ImmutableList<Aspect> getAspects() {
300 return aspects;
301 }
302
303 /**
cparsonse8d450c2018-10-04 16:01:53 -0700304 * If this target's configuration suppresses analysis failures, this returns a list
305 * of strings, where each string corresponds to a description of an error that occurred during
306 * processing this target.
307 *
308 * @throws IllegalStateException if this target's configuration does not suppress analysis
309 * failures (if {@code getConfiguration().allowAnalysisFailures()} is false)
310 */
311 public List<String> getSuppressedErrorMessages() {
312 Preconditions.checkState(getConfiguration().allowAnalysisFailures(),
313 "Error messages can only be retrieved via RuleContext if allow_analysis_failures is true");
314 Preconditions.checkState(reporter instanceof SuppressingErrorReporter,
315 "Unexpected error reporter");
316 return ((SuppressingErrorReporter) reporter).getErrorMessages();
317 }
318
319 /**
dslomov44d15712017-12-20 05:42:28 -0800320 * If this <code>RuleContext</code> is for an aspect implementation, returns that aspect.
321 * (it is the last aspect in the list of aspects applied to a target; all other aspects
322 * are the ones main aspect sees as specified by its "required_aspect_providers")
323 * Otherwise returns <code>null</code>.
324 */
325 @Nullable
326 public Aspect getMainAspect() {
327 return aspects.isEmpty() ? null : aspects.get(aspects.size() - 1);
328 }
329
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100330 /**
Michael Staib8824d5e2016-01-20 21:37:05 +0000331 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
332 */
333 public String getRuleClassNameForLogging() {
334 return ruleClassNameForLogging;
335 }
336
337 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +0000338 * Returns the workspace name for the rule.
339 */
340 public String getWorkspaceName() {
kchodorow85ae1902017-04-22 15:07:22 -0400341 return rule.getRepository().strippedName();
Kristina Chodorow91876f02015-02-27 17:14:12 +0000342 }
343
344 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100345 * The configuration conditions that trigger this rule's configurable attributes.
346 */
gregce593f7f92017-09-19 02:02:21 +0200347 public ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100348 return configConditions;
349 }
350
351 /**
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000352 * Returns the host configuration for this rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100353 */
354 public BuildConfiguration getHostConfiguration() {
Greg Estren9eb1cf02015-06-26 22:18:35 +0000355 return hostConfiguration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100356 }
357
358 /**
Dmitry Lomov503c2f72017-02-23 08:55:47 +0000359 * All aspects applied to the rule.
360 */
361 public ImmutableList<AspectDescriptor> getAspectDescriptors() {
362 return aspectDescriptors;
363 }
364
365 /**
Greg Estren7f534232016-12-01 21:38:25 +0000366 * Accessor for the attributes of the rule and its aspects.
367 *
368 * <p>The rule's native attributes can be queried both on their structure / existence and values
369 * Aspect attributes can only be queried on their structure.
370 *
371 * <p>This should be the sole interface for reading rule/aspect attributes in {@link RuleContext}.
372 * Don't expose other access points through new public methods.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100373 */
374 public AttributeMap attributes() {
375 return attributes;
376 }
377
cparsons0dcffc52017-10-13 23:40:31 +0200378 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100379 public boolean hasErrors() {
cparsons146b9ff2019-06-21 09:45:14 -0700380 return reporter.hasErrors();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100381 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000382
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100383 /**
384 * Returns an immutable map from attribute name to list of configured targets for that attribute.
385 */
386 public ListMultimap<String, ? extends TransitiveInfoCollection> getConfiguredTargetMap() {
janakr9c101402018-03-10 06:48:59 -0800387 return Multimaps.transformValues(targetMap, ConfiguredTargetAndData::getConfiguredTarget);
janakrf3e6f252018-01-18 07:45:12 -0800388 }
389
janakr65866212018-03-10 22:30:33 -0800390 /**
391 * Returns an immutable map from attribute name to list of {@link ConfiguredTargetAndData} objects
392 * for that attribute.
393 */
394 public ListMultimap<String, ConfiguredTargetAndData> getConfiguredTargetAndDataMap() {
395 return targetMap;
396 }
397
janakr9c101402018-03-10 06:48:59 -0800398 private List<ConfiguredTargetAndData> getConfiguredTargetAndTargetDeps(String key) {
mjhalupkade47f212018-02-12 12:31:21 -0800399 return targetMap.get(key);
400 }
401
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100402 /**
403 * Returns an immutable map from attribute name to list of fileset entries.
404 */
405 public ListMultimap<String, ConfiguredFilesetEntry> getFilesetEntryMap() {
406 return filesetEntryMap;
407 }
408
409 @Override
410 public ActionOwner getActionOwner() {
411 if (actionOwner == null) {
John Caterec5d2ed2018-01-04 11:52:21 -0800412 actionOwner =
413 createActionOwner(rule, aspectDescriptors, getConfiguration(), getExecutionPlatform());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100414 }
415 return actionOwner;
416 }
417
418 /**
plf1f341a62019-04-01 14:02:14 -0700419 * We have to re-implement this method here because it is declared in the interface {@link
420 * ActionConstructionContext}. This class inherits from {@link TargetContext} which doesn't
421 * implement the {@link ActionConstructionContext} interface.
422 */
423 @Override
424 public ActionKeyContext getActionKeyContext() {
425 return super.getActionKeyContext();
426 }
427
428 /**
janakreaff19c2019-01-31 13:59:40 -0800429 * An opaque symbol generator to be used when identifying objects by their action owner/index of
430 * creation. Only needed if an object needs to know whether it was created by the same action
431 * owner in the same order as another object. Each symbol must call {@link
432 * SymbolGenerator#generate} separately to obtain a unique object.
433 */
434 public SymbolGenerator<?> getSymbolGenerator() {
435 return actionOwnerSymbolGenerator;
436 }
437
438 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100439 * Returns a configuration fragment for this this target.
440 */
441 @Nullable
gregcebe55e112018-01-30 11:04:53 -0800442 public <T extends Fragment> T getFragment(Class<T> fragment, ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800443 return getFragment(fragment, fragment.getSimpleName(), "", transition);
Florian Weikertd2a24612015-09-07 14:35:23 +0000444 }
445
446 @Nullable
447 protected <T extends Fragment> T getFragment(Class<T> fragment, String name,
gregcebe55e112018-01-30 11:04:53 -0800448 String additionalErrorMessage, ConfigurationTransition transition) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100449 // TODO(bazel-team): The fragments can also be accessed directly through BuildConfiguration.
450 // Can we lock that down somehow?
gregcec7b21212017-12-21 12:40:20 -0800451 Preconditions.checkArgument(isLegalFragment(fragment, transition),
Florian Weikertd2a24612015-09-07 14:35:23 +0000452 "%s has to declare '%s' as a required fragment "
453 + "in %s configuration in order to access it.%s",
gregcec7b21212017-12-21 12:40:20 -0800454 getRuleClassNameForLogging(), name, FragmentCollection.getConfigurationName(transition),
Florian Weikertd2a24612015-09-07 14:35:23 +0000455 additionalErrorMessage);
gregcec7b21212017-12-21 12:40:20 -0800456 return getConfiguration(transition).getFragment(fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100457 }
458
Florian Weikert082c0542015-08-06 10:24:29 +0000459 @Nullable
Florian Weikert3f8aac92015-09-07 12:06:02 +0000460 public <T extends Fragment> T getFragment(Class<T> fragment) {
gregce7fa23ea2018-01-18 12:46:04 -0800461 // No transition means target configuration.
462 return getFragment(fragment, NoTransition.INSTANCE);
Florian Weikert082c0542015-08-06 10:24:29 +0000463 }
464
Florian Weikert3f8aac92015-09-07 12:06:02 +0000465 @Nullable
gregcebe55e112018-01-30 11:04:53 -0800466 public Fragment getSkylarkFragment(String name, ConfigurationTransition transition) {
Florian Weikert1c2eeac2015-10-28 10:00:53 +0000467 Class<? extends Fragment> fragmentClass =
gregcec7b21212017-12-21 12:40:20 -0800468 getConfiguration(transition).getSkylarkFragmentByName(name);
Florian Weikertd2a24612015-09-07 14:35:23 +0000469 if (fragmentClass == null) {
470 return null;
471 }
472 return getFragment(fragmentClass, name,
473 String.format(
474 " Please update the '%1$sfragments' argument of the rule definition "
475 + "(for example: %1$sfragments = [\"%2$s\"])",
gregcec7b21212017-12-21 12:40:20 -0800476 (transition.isHostTransition()) ? "host_" : "", name),
477 transition);
Florian Weikert3f8aac92015-09-07 12:06:02 +0000478 }
479
gregcebe55e112018-01-30 11:04:53 -0800480 public ImmutableCollection<String> getSkylarkFragmentNames(ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800481 return getConfiguration(transition).getSkylarkFragmentNames();
Florian Weikert3f8aac92015-09-07 12:06:02 +0000482 }
483
484 public <T extends Fragment> boolean isLegalFragment(
gregcebe55e112018-01-30 11:04:53 -0800485 Class<T> fragment, ConfigurationTransition transition) {
lberki78651d42018-04-06 01:52:58 -0700486 return universalFragments.contains(fragment)
cpeysera399b7c2017-09-19 18:19:27 +0200487 || fragment == PlatformConfiguration.class
gregcec7b21212017-12-21 12:40:20 -0800488 || configurationFragmentPolicy.isLegalConfigurationFragment(fragment, transition);
Florian Weikert082c0542015-08-06 10:24:29 +0000489 }
490
Ulf Adamsea11fc52015-08-04 14:23:58 +0000491 public <T extends Fragment> boolean isLegalFragment(Class<T> fragment) {
gregce7fa23ea2018-01-18 12:46:04 -0800492 // No transition means target configuration.
493 return isLegalFragment(fragment, NoTransition.INSTANCE);
Florian Weikert3f8aac92015-09-07 12:06:02 +0000494 }
Florian Weikertd2a24612015-09-07 14:35:23 +0000495
gregcee861ffc2018-02-02 17:06:49 -0800496 private BuildConfiguration getConfiguration(ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800497 return transition.isHostTransition() ? hostConfiguration : getConfiguration();
Ulf Adamsea11fc52015-08-04 14:23:58 +0000498 }
499
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100500 @Override
janakr658d47f2019-05-29 11:11:30 -0700501 public ActionLookupValue.ActionLookupKey getOwner() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100502 return getAnalysisEnvironment().getOwner();
503 }
504
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000505 public ImmutableList<Artifact> getBuildInfo(BuildInfoKey key) throws InterruptedException {
plf1f341a62019-04-01 14:02:14 -0700506 return getAnalysisEnvironment()
507 .getBuildInfo(
508 AnalysisUtils.isStampingEnabled(this, getConfiguration()), key, getConfiguration());
Ulf Adamsc272e0f2015-04-22 19:56:21 +0000509 }
510
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000511 @VisibleForTesting
Carmi Grushko33aa3062016-11-11 02:45:29 +0000512 public static ActionOwner createActionOwner(
513 Rule rule,
Dmitry Lomov15756522016-12-16 16:52:37 +0000514 ImmutableList<AspectDescriptor> aspectDescriptors,
John Caterec5d2ed2018-01-04 11:52:21 -0800515 BuildConfiguration configuration,
516 @Nullable PlatformInfo executionPlatform) {
Googler0dc53a22019-08-25 22:09:56 -0700517 ImmutableMap<String, String> execProperties;
518 if (executionPlatform != null) {
519 execProperties = executionPlatform.execProperties();
520 } else {
521 execProperties = ImmutableMap.of();
522 }
523 // TODO(agoulti): Insert logic to include per-target execution properties
524
Carmi Grushko4665e702016-11-09 21:51:27 +0000525 return ActionOwner.create(
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000526 rule.getLabel(),
Dmitry Lomov15756522016-12-16 16:52:37 +0000527 aspectDescriptors,
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000528 rule.getLocation(),
529 configuration.getMnemonic(),
530 rule.getTargetKind(),
531 configuration.checksum(),
shahan50f99d52018-03-10 05:14:09 -0800532 configuration.toBuildEvent(),
John Caterec5d2ed2018-01-04 11:52:21 -0800533 configuration.isHostConfiguration() ? HOST_CONFIGURATION_PROGRESS_TAG : null,
Googler0dc53a22019-08-25 22:09:56 -0700534 execProperties,
John Caterec5d2ed2018-01-04 11:52:21 -0800535 executionPlatform);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100536 }
537
538 @Override
Rumou Duan33bab462016-04-25 17:55:12 +0000539 public void registerAction(ActionAnalysisMetadata... action) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100540 getAnalysisEnvironment().registerAction(action);
541 }
542
543 /**
544 * Convenience function for subclasses to report non-attribute-specific
545 * errors in the current rule.
546 */
547 @Override
548 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000549 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100550 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000551
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100552 /**
553 * Convenience function for subclasses to report non-attribute-specific
554 * warnings in the current rule.
555 */
556 @Override
557 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000558 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100559 }
560
561 /**
562 * Convenience function for subclasses to report attribute-specific errors in
563 * the current rule.
564 *
565 * <p>If the name of the attribute starts with <code>$</code>
566 * it is replaced with a string <code>(an implicit dependency)</code>.
567 */
568 @Override
569 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000570 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100571 }
572
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000573 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100574 * Like attributeError, but does not mark the configured target as errored.
575 *
576 * <p>If the name of the attribute starts with <code>$</code>
577 * it is replaced with a string <code>(an implicit dependency)</code>.
578 */
579 @Override
580 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000581 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100582 }
583
584 /**
585 * Returns an artifact beneath the root of either the "bin" or "genfiles"
586 * tree, whose path is based on the name of this target and the current
587 * configuration. The choice of which tree to use is based on the rule with
588 * which this target (which must be an OutputFile or a Rule) is associated.
589 */
590 public Artifact createOutputArtifact() {
cparsons0623d3c2018-10-23 16:06:30 -0700591 Target target = getTarget();
592 PathFragment rootRelativePath = getPackageDirectory()
593 .getRelative(PathFragment.create(target.getName()));
594
595 return internalCreateOutputArtifact(rootRelativePath, target, OutputFile.Kind.FILE);
596 }
597
598 /**
599 * Returns an artifact beneath the root of either the "bin" or "genfiles"
600 * tree, whose path is based on the name of this target and the current
601 * configuration, with a script suffix appropriate for the current host platform. ({@code .cmd}
602 * for Windows, otherwise {@code .sh}). The choice of which tree to use is based on the rule with
603 * which this target (which must be an OutputFile or a Rule) is associated.
604 */
605 public Artifact createOutputArtifactScript() {
606 Target target = getTarget();
607 // TODO(laszlocsomor): Use the execution platform, not the host platform.
608 boolean isExecutedOnWindows = OS.getCurrent() == OS.WINDOWS;
609
610 String fileExtension = isExecutedOnWindows ? ".cmd" : ".sh";
611
612 PathFragment rootRelativePath = getPackageDirectory()
613 .getRelative(PathFragment.create(target.getName() + fileExtension));
614
615 return internalCreateOutputArtifact(rootRelativePath, target, OutputFile.Kind.FILE);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100616 }
617
618 /**
619 * Returns the output artifact of an {@link OutputFile} of this target.
620 *
621 * @see #createOutputArtifact()
622 */
623 public Artifact createOutputArtifact(OutputFile out) {
cparsons0623d3c2018-10-23 16:06:30 -0700624 PathFragment packageRelativePath = getPackageDirectory()
625 .getRelative(PathFragment.create(out.getName()));
626 return internalCreateOutputArtifact(packageRelativePath, out, out.getKind());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100627 }
628
629 /**
630 * Implementation for {@link #createOutputArtifact()} and
631 * {@link #createOutputArtifact(OutputFile)}. This is private so that
632 * {@link #createOutputArtifact(OutputFile)} can have a more specific
633 * signature.
634 */
cparsons0623d3c2018-10-23 16:06:30 -0700635 private Artifact internalCreateOutputArtifact(PathFragment rootRelativePath,
636 Target target, OutputFile.Kind outputFileKind) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000637 Preconditions.checkState(
638 target.getLabel().getPackageIdentifier().equals(getLabel().getPackageIdentifier()),
639 "Creating output artifact for target '%s' in different package than the rule '%s' "
640 + "being analyzed", target.getLabel(), getLabel());
tomlu1cdcdf92018-01-16 11:07:51 -0800641 ArtifactRoot root = getBinOrGenfilesDirectory();
cparsons0623d3c2018-10-23 16:06:30 -0700642
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700643 switch (outputFileKind) {
644 case FILE:
cparsons0623d3c2018-10-23 16:06:30 -0700645 return getDerivedArtifact(rootRelativePath, root);
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700646 case FILESET:
cparsons0623d3c2018-10-23 16:06:30 -0700647 return getAnalysisEnvironment().getFilesetArtifact(rootRelativePath, root);
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700648 default:
649 throw new IllegalStateException();
650 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100651 }
652
653 /**
tomlu1cdcdf92018-01-16 11:07:51 -0800654 * Returns the root of either the "bin" or "genfiles" tree, based on this target and the current
655 * configuration. The choice of which tree to use is based on the rule with which this target
656 * (which must be an OutputFile or a Rule) is associated.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100657 */
tomlu1cdcdf92018-01-16 11:07:51 -0800658 public ArtifactRoot getBinOrGenfilesDirectory() {
Kristina Chodorowba41c2d2016-10-10 17:21:24 +0000659 return rule.hasBinaryOutput()
660 ? getConfiguration().getBinDirectory(rule.getRepository())
661 : getConfiguration().getGenfilesDirectory(rule.getRepository());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100662 }
663
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000664 /**
tomlu1cdcdf92018-01-16 11:07:51 -0800665 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
666 * guaranteeing that it never clashes with artifacts created by rules in other packages.
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000667 */
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000668 public Artifact getBinArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000669 return getBinArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000670 }
671
672 public Artifact getBinArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000673 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000674 relative, getConfiguration().getBinDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000675 }
676
677 /**
678 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
679 * guaranteeing that it never clashes with artifacts created by rules in other packages.
680 */
681 public Artifact getGenfilesArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000682 return getGenfilesArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000683 }
684
685 public Artifact getGenfilesArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000686 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000687 relative, getConfiguration().getGenfilesDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000688 }
689
plfb74df042018-10-31 02:15:10 -0700690 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800691 public Artifact getShareableArtifact(PathFragment rootRelativePath, ArtifactRoot root) {
Lukacs Berki21a04f22015-08-20 13:31:24 +0000692 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root);
693 }
694
asteinb0de45462018-05-17 08:07:12 -0700695 @Override
janakr658d47f2019-05-29 11:11:30 -0700696 public Artifact.DerivedArtifact getPackageRelativeArtifact(
697 PathFragment relative, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700698 return getPackageRelativeArtifact(relative, root, /*contentBasedPath=*/ false);
699 }
700
701 /**
702 * Same as {@link #getPackageRelativeArtifact(PathFragment, ArtifactRoot)} but includes the option
703 * option to use a content-based path for this artifact (see {@link
704 * BuildConfiguration#useContentBasedOutputPaths()}).
705 */
706 private Artifact.DerivedArtifact getPackageRelativeArtifact(
707 PathFragment relative, ArtifactRoot root, boolean contentBasedPath) {
708 return getDerivedArtifact(getPackageDirectory().getRelative(relative), root, contentBasedPath);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000709 }
710
janakr658d47f2019-05-29 11:11:30 -0700711 /**
712 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
713 * guaranteeing that it never clashes with artifacts created by rules in other packages.
714 */
715 public Artifact getPackageRelativeArtifact(String relative, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700716 return getPackageRelativeArtifact(relative, root, /*contentBasedPath=*/ false);
717 }
718
719 /**
720 * Same as {@link #getPackageRelativeArtifact(String, ArtifactRoot)} but includes the option to
721 * use a content-based path for this artifact (see {@link
722 * BuildConfiguration#useContentBasedOutputPaths()}).
723 */
724 private Artifact getPackageRelativeArtifact(
725 String relative, ArtifactRoot root, boolean contentBasedPath) {
726 return getPackageRelativeArtifact(PathFragment.create(relative), root, contentBasedPath);
janakr658d47f2019-05-29 11:11:30 -0700727 }
728
asteinb0de45462018-05-17 08:07:12 -0700729 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000730 public PathFragment getPackageDirectory() {
Dmitry Lomove36a66c2017-02-17 14:48:48 +0000731 return getLabel().getPackageIdentifier().getSourceRoot();
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000732 }
733
734 /**
735 * Creates an artifact under a given root with the given root-relative path.
736 *
737 * <p>Verifies that it is in the root-relative directory corresponding to the package of the rule,
738 * thus ensuring that it doesn't clash with other artifacts generated by other rules using this
739 * method.
740 */
Ulf Adams3ab82f72015-09-04 12:10:53 +0000741 @Override
janakr658d47f2019-05-29 11:11:30 -0700742 public Artifact.DerivedArtifact getDerivedArtifact(
743 PathFragment rootRelativePath, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700744 return getDerivedArtifact(rootRelativePath, root, /*contentBasedPath=*/ false);
745 }
746
747 /**
748 * Same as {@link #getDerivedArtifact(PathFragment, ArtifactRoot)} but includes the option to use
749 * a content-based path for this artifact (see {@link
750 * BuildConfiguration#useContentBasedOutputPaths()}).
751 */
752 public Artifact.DerivedArtifact getDerivedArtifact(
753 PathFragment rootRelativePath, ArtifactRoot root, boolean contentBasedPath) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000754 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
755 "Output artifact '%s' not under package directory '%s' for target '%s'",
756 rootRelativePath, getPackageDirectory(), getLabel());
gregce11f3b0e2019-06-07 17:12:06 -0700757 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root, contentBasedPath);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000758 }
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000759
plf441fd752019-02-06 01:28:18 -0800760 @Override
cpeyserac09f0a2018-02-05 09:33:15 -0800761 public SpecialArtifact getTreeArtifact(PathFragment rootRelativePath, ArtifactRoot root) {
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000762 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
763 "Output artifact '%s' not under package directory '%s' for target '%s'",
764 rootRelativePath, getPackageDirectory(), getLabel());
765 return getAnalysisEnvironment().getTreeArtifact(rootRelativePath, root);
766 }
767
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000768 /**
allevato060a4482017-03-30 20:45:52 +0000769 * Creates a tree artifact in a directory that is unique to the package that contains the rule,
770 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
771 */
tomlu1cdcdf92018-01-16 11:07:51 -0800772 public Artifact getPackageRelativeTreeArtifact(PathFragment relative, ArtifactRoot root) {
allevato060a4482017-03-30 20:45:52 +0000773 return getTreeArtifact(getPackageDirectory().getRelative(relative), root);
774 }
775
776 /**
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000777 * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
778 * clashes with artifacts created by other rules.
779 */
780 public Artifact getUniqueDirectoryArtifact(
tomlu1cdcdf92018-01-16 11:07:51 -0800781 String uniqueDirectory, String relative, ArtifactRoot root) {
nharmatab4060b62017-04-04 17:11:39 +0000782 return getUniqueDirectoryArtifact(uniqueDirectory, PathFragment.create(relative), root);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000783 }
784
asteinb0de45462018-05-17 08:07:12 -0700785 @Override
786 public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String relative) {
787 return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
788 }
789
ahumesky4b00ab12018-11-15 16:23:46 -0800790 @Override
791 public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
792 return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
793 }
794
plf727a07d2019-02-01 02:27:35 -0800795 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000796 public Artifact getUniqueDirectoryArtifact(
tomlu1cdcdf92018-01-16 11:07:51 -0800797 String uniqueDirectory, PathFragment relative, ArtifactRoot root) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000798 return getDerivedArtifact(getUniqueDirectory(uniqueDirectory).getRelative(relative), root);
799 }
800
Googler03083852015-12-06 18:31:53 +0000801 /**
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000802 * Returns true iff the rule, or any attached aspect, has an attribute with the given name and
803 * type.
804 */
805 public boolean isAttrDefined(String attrName, Type<?> type) {
Greg Estren7f534232016-12-01 21:38:25 +0000806 return attributes().has(attrName, type);
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000807 }
808
809 /**
Lukacs Berki8bdae762016-07-13 14:58:54 +0000810 * Returns the dependencies through a {@code LABEL_DICT_UNARY} attribute as a map from
811 * a string to a {@link TransitiveInfoCollection}.
812 */
813 public Map<String, TransitiveInfoCollection> getPrerequisiteMap(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +0000814 Preconditions.checkState(attributes().has(attributeName, BuildType.LABEL_DICT_UNARY));
Lukacs Berki8bdae762016-07-13 14:58:54 +0000815
816 ImmutableMap.Builder<String, TransitiveInfoCollection> result = ImmutableMap.builder();
817 Map<String, Label> dict = attributes().get(attributeName, BuildType.LABEL_DICT_UNARY);
818 Map<Label, ConfiguredTarget> labelToDep = new HashMap<>();
janakr9c101402018-03-10 06:48:59 -0800819 for (ConfiguredTargetAndData dep : targetMap.get(attributeName)) {
janakrf3e6f252018-01-18 07:45:12 -0800820 labelToDep.put(dep.getTarget().getLabel(), dep.getConfiguredTarget());
Lukacs Berki8bdae762016-07-13 14:58:54 +0000821 }
822
823 for (Map.Entry<String, Label> entry : dict.entrySet()) {
824 result.put(entry.getKey(), Preconditions.checkNotNull(labelToDep.get(entry.getValue())));
825 }
826
827 return result.build();
828 }
829
830 /**
gregce46e7fe22018-04-06 13:21:18 -0700831 * Returns the prerequisites keyed by the CPU of their configurations. If the split transition
mjhalupkade47f212018-02-12 12:31:21 -0800832 * is not active (e.g. split() returned an empty list), the key is an empty Optional.
833 */
834 public Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>>
835 getSplitPrerequisites(String attributeName) {
836 return Maps.transformValues(
837 getSplitPrerequisiteConfiguredTargetAndTargets(attributeName),
janakr9c101402018-03-10 06:48:59 -0800838 (ctatList) -> Lists.transform(ctatList, ConfiguredTargetAndData::getConfiguredTarget));
mjhalupkade47f212018-02-12 12:31:21 -0800839 }
840
841 /**
842 * Returns the list of ConfiguredTargetsAndTargets that feed into the target through the specified
843 * attribute. Note that you need to specify the correct mode for the attribute otherwise an
844 * exception will be raised.
845 */
janakr9c101402018-03-10 06:48:59 -0800846 public List<ConfiguredTargetAndData> getPrerequisiteConfiguredTargetAndTargets(
mjhalupkade47f212018-02-12 12:31:21 -0800847 String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +0000848 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
jcatere8f5a982019-04-02 11:12:19 -0700849 if ((mode == Mode.TARGET) && (attributeDefinition.getTransitionFactory().isSplit())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100850 // TODO(bazel-team): If you request a split-configured attribute in the target configuration,
851 // we return only the list of configured targets for the first architecture; this is for
852 // backwards compatibility with existing code in cases where the call to getPrerequisites is
853 // deeply nested and we can't easily inject the behavior we want. However, we should fix all
854 // such call sites.
855 checkAttribute(attributeName, Mode.SPLIT);
janakr9c101402018-03-10 06:48:59 -0800856 Map<Optional<String>, List<ConfiguredTargetAndData>> map =
mjhalupkade47f212018-02-12 12:31:21 -0800857 getSplitPrerequisiteConfiguredTargetAndTargets(attributeName);
dslomovde965ac2017-07-31 21:07:51 +0200858 return map.isEmpty() ? ImmutableList.of() : map.entrySet().iterator().next().getValue();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100859 }
860
861 checkAttribute(attributeName, mode);
mjhalupkade47f212018-02-12 12:31:21 -0800862 return getConfiguredTargetAndTargetDeps(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100863 }
864
janakr0758d352018-03-10 20:38:45 -0800865 /**
866 * Returns the prerequisites keyed by the CPU of their configurations. If the split transition is
867 * not active (e.g. split() returned an empty list), the key is an empty Optional.
868 */
869 public Map<Optional<String>, List<ConfiguredTargetAndData>>
mjhalupkade47f212018-02-12 12:31:21 -0800870 getSplitPrerequisiteConfiguredTargetAndTargets(String attributeName) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100871 checkAttribute(attributeName, Mode.SPLIT);
Greg Estren7f534232016-12-01 21:38:25 +0000872 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
jcatere8f5a982019-04-02 11:12:19 -0700873 Preconditions.checkState(attributeDefinition.getTransitionFactory().isSplit());
mjhalupkade47f212018-02-12 12:31:21 -0800874 SplitTransition transition =
John Cater5adcd3e2019-03-28 10:14:32 -0700875 (SplitTransition)
876 attributeDefinition
877 .getTransitionFactory()
878 .create(
jcater23589462019-05-20 08:51:24 -0700879 AttributeTransitionData.builder()
880 .attributes(ConfiguredAttributeMapper.of(rule, configConditions))
881 .executionPlatform(getToolchainContext().executionPlatform().label())
882 .build());
gregce1cc0dec2018-05-23 12:44:23 -0700883 BuildOptions fromOptions = getConfiguration().getOptions();
gregce806678d2018-05-23 15:30:22 -0700884 List<BuildOptions> splitOptions = transition.split(fromOptions);
janakr9c101402018-03-10 06:48:59 -0800885 List<ConfiguredTargetAndData> deps = getConfiguredTargetAndTargetDeps(attributeName);
mjhalupkade47f212018-02-12 12:31:21 -0800886
gregce1cc0dec2018-05-23 12:44:23 -0700887 if (SplitTransition.equals(fromOptions, splitOptions)) {
Googler59480b92016-07-22 17:06:40 +0000888 // The split transition is not active. Defer the decision on which CPU to use.
Greg Estren66cadd32016-08-05 21:07:02 +0000889 return ImmutableMap.of(Optional.<String>absent(), deps);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100890 }
891
892 Set<String> cpus = new HashSet<>();
Greg Estren66cadd32016-08-05 21:07:02 +0000893 for (BuildOptions options : splitOptions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100894 // This method should only be called when the split config is enabled on the command line, in
895 // which case this cpu can't be null.
gregcee495e6b2019-04-30 14:07:06 -0700896 cpus.add(options.get(CoreOptions.class).cpu);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100897 }
898
899 // Use an ImmutableListMultimap.Builder here to preserve ordering.
janakr9c101402018-03-10 06:48:59 -0800900 ImmutableListMultimap.Builder<Optional<String>, ConfiguredTargetAndData> result =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100901 ImmutableListMultimap.builder();
janakr9c101402018-03-10 06:48:59 -0800902 for (ConfiguredTargetAndData t : deps) {
janakr163b3922018-03-10 16:24:52 -0800903 if (t.getConfiguration() != null) {
904 result.put(Optional.of(t.getConfiguration().getCpu()), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100905 } else {
906 // Source files don't have a configuration, so we add them to all architecture entries.
907 for (String cpu : cpus) {
Googler59480b92016-07-22 17:06:40 +0000908 result.put(Optional.of(cpu), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100909 }
910 }
911 }
912 return Multimaps.asMap(result.build());
913 }
914
915 /**
916 * Returns the specified provider of the prerequisite referenced by the attribute in the
917 * argument. Note that you need to specify the correct mode for the attribute, otherwise an
gregce47d57852017-06-26 23:01:54 +0200918 * assertion will be raised. If the attribute is empty or it does not support the specified
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100919 * provider, returns null.
920 */
921 public <C extends TransitiveInfoProvider> C getPrerequisite(
922 String attributeName, Mode mode, Class<C> provider) {
923 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
924 return prerequisite == null ? null : prerequisite.getProvider(provider);
925 }
926
927 /**
928 * Returns the transitive info collection that feeds into this target through the specified
929 * attribute. Note that you need to specify the correct mode for the attribute, otherwise an
930 * assertion will be raised. Returns null if the attribute is empty.
931 */
932 public TransitiveInfoCollection getPrerequisite(String attributeName, Mode mode) {
janakr27bb6dd2018-03-10 19:10:00 -0800933 ConfiguredTargetAndData result = getPrerequisiteConfiguredTargetAndData(attributeName, mode);
934 return result == null ? null : result.getConfiguredTarget();
935 }
936
937 /**
938 * Returns the {@link ConfiguredTargetAndData} that feeds ino this target through the specified
939 * attribute. Note that you need to specify the correct mode for the attribute, otherwise an
940 * assertion will be raised. Returns null if the attribute is empty.
941 */
942 public ConfiguredTargetAndData getPrerequisiteConfiguredTargetAndData(
943 String attributeName, Mode mode) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100944 checkAttribute(attributeName, mode);
janakr27bb6dd2018-03-10 19:10:00 -0800945 List<ConfiguredTargetAndData> elements = getConfiguredTargetAndTargetDeps(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100946 if (elements.size() > 1) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000947 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
948 + " produces more than one prerequisite");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100949 }
950 return elements.isEmpty() ? null : elements.get(0);
951 }
952
953 /**
mjhalupkade47f212018-02-12 12:31:21 -0800954 * For a given attribute, returns all the ConfiguredTargetAndTargets of that attribute. Each
janakr9c101402018-03-10 06:48:59 -0800955 * ConfiguredTargetAndData is keyed by the {@link BuildConfiguration} that created it.
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000956 */
janakr9c101402018-03-10 06:48:59 -0800957 public ImmutableListMultimap<BuildConfiguration, ConfiguredTargetAndData>
mjhalupkade47f212018-02-12 12:31:21 -0800958 getPrerequisiteCofiguredTargetAndTargetsByConfiguration(String attributeName, Mode mode) {
janakr9c101402018-03-10 06:48:59 -0800959 List<ConfiguredTargetAndData> ctatCollection =
mjhalupkade47f212018-02-12 12:31:21 -0800960 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode);
janakr9c101402018-03-10 06:48:59 -0800961 ImmutableListMultimap.Builder<BuildConfiguration, ConfiguredTargetAndData> result =
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000962 ImmutableListMultimap.builder();
janakr9c101402018-03-10 06:48:59 -0800963 for (ConfiguredTargetAndData ctad : ctatCollection) {
janakr163b3922018-03-10 16:24:52 -0800964 result.put(ctad.getConfiguration(), ctad);
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000965 }
966 return result.build();
967 }
968
969 /**
dslomovde965ac2017-07-31 21:07:51 +0200970 * For a given attribute, returns all declared provider provided by targets of that attribute.
971 * Each declared provider is keyed by the {@link BuildConfiguration} under which the provider was
972 * created.
cparsons075ab1e2018-08-07 14:20:20 -0700973 *
974 * @deprecated use {@link #getPrerequisitesByConfiguration(String, Mode, BuiltinProvider)}
975 * instead
976 */
977 @Deprecated
978 public <C extends Info>
979 ImmutableListMultimap<BuildConfiguration, C> getPrerequisitesByConfiguration(
980 String attributeName, Mode mode, final NativeProvider<C> provider) {
981 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
982 ImmutableListMultimap.builder();
983 for (ConfiguredTargetAndData prerequisite :
984 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode)) {
985 C prerequisiteProvider = prerequisite.getConfiguredTarget().get(provider);
986 if (prerequisiteProvider != null) {
987 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
988 }
989 }
990 return result.build();
991 }
992
993 /**
994 * For a given attribute, returns all declared provider provided by targets of that attribute.
995 * Each declared provider is keyed by the {@link BuildConfiguration} under which the provider was
996 * created.
dslomov4e9fa192017-07-12 14:59:07 +0200997 */
dslomovde965ac2017-07-31 21:07:51 +0200998 public <C extends Info>
999 ImmutableListMultimap<BuildConfiguration, C> getPrerequisitesByConfiguration(
cparsons075ab1e2018-08-07 14:20:20 -07001000 String attributeName, Mode mode, final BuiltinProvider<C> provider) {
dslomov4e9fa192017-07-12 14:59:07 +02001001 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
1002 ImmutableListMultimap.builder();
janakr12b78fe2018-03-10 18:06:56 -08001003 for (ConfiguredTargetAndData prerequisite :
1004 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode)) {
1005 C prerequisiteProvider = prerequisite.getConfiguredTarget().get(provider);
dslomov4e9fa192017-07-12 14:59:07 +02001006 if (prerequisiteProvider != null) {
1007 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
1008 }
1009 }
1010 return result.build();
1011 }
1012
1013 /**
Chris Parsons0d7f0412016-04-29 20:35:44 +00001014 * For a given attribute, returns all {@link TransitiveInfoCollection}s provided by targets
1015 * of that attribute. Each {@link TransitiveInfoCollection} is keyed by the
1016 * {@link BuildConfiguration} under which the collection was created.
1017 */
1018 public ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection>
1019 getPrerequisitesByConfiguration(String attributeName, Mode mode) {
Chris Parsons0d7f0412016-04-29 20:35:44 +00001020 ImmutableListMultimap.Builder<BuildConfiguration, TransitiveInfoCollection> result =
1021 ImmutableListMultimap.builder();
janakr12b78fe2018-03-10 18:06:56 -08001022 for (ConfiguredTargetAndData prerequisite :
1023 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode)) {
1024 result.put(prerequisite.getConfiguration(), prerequisite.getConfiguredTarget());
Chris Parsons0d7f0412016-04-29 20:35:44 +00001025 }
1026 return result.build();
1027 }
1028
1029 /**
cparsonsb35c0a42018-08-20 11:37:41 -07001030 * Returns the list of transitive info collections that feed into this target through the
1031 * specified attribute. Note that you need to specify the correct mode for the attribute,
1032 * otherwise an assertion will be raised.
1033 */
1034 public List<? extends TransitiveInfoCollection> getPrerequisites(String attributeName,
1035 Mode mode) {
1036 return Lists.transform(
1037 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode),
1038 ConfiguredTargetAndData::getConfiguredTarget);
1039 }
1040
1041 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001042 * Returns all the providers of the specified type that are listed under the specified attribute
1043 * of this target in the BUILD file.
1044 */
1045 public <C extends TransitiveInfoProvider> Iterable<C> getPrerequisites(String attributeName,
1046 Mode mode, final Class<C> classType) {
1047 AnalysisUtils.checkProvider(classType);
1048 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), classType);
1049 }
1050
1051 /**
Sergio Campamafd931432016-12-09 21:47:35 +00001052 * Returns all the declared providers (native and Skylark) for the specified constructor under the
1053 * specified attribute of this target in the BUILD file.
1054 */
cparsons4ebf6c02018-08-17 14:49:36 -07001055 public <T extends InfoInterface> Iterable<T> getPrerequisites(
dslomovde965ac2017-07-31 21:07:51 +02001056 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
dslomov77baa4c2017-07-10 17:15:27 +02001057 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), skylarkKey);
Sergio Campamafd931432016-12-09 21:47:35 +00001058 }
1059
1060 /**
cparsons2d67cf92018-05-24 14:02:09 -07001061 * Returns all the declared providers (native and Skylark) for the specified constructor under the
1062 * specified attribute of this target in the BUILD file.
1063 */
cparsons4ebf6c02018-08-17 14:49:36 -07001064 public <T extends InfoInterface> Iterable<T> getPrerequisites(
cparsons2d67cf92018-05-24 14:02:09 -07001065 String attributeName, Mode mode, final BuiltinProvider<T> skylarkKey) {
1066 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), skylarkKey);
1067 }
1068
1069 /**
Sergio Campamae8cecd92016-12-13 18:49:28 +00001070 * Returns the declared provider (native and Skylark) for the specified constructor under the
1071 * specified attribute of this target in the BUILD file. May return null if there is no
1072 * TransitiveInfoCollection under the specified attribute.
1073 */
1074 @Nullable
cparsons4ebf6c02018-08-17 14:49:36 -07001075 public <T extends InfoInterface> T getPrerequisite(
dslomovde965ac2017-07-31 21:07:51 +02001076 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
Sergio Campamae8cecd92016-12-13 18:49:28 +00001077 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
1078 return prerequisite == null ? null : prerequisite.get(skylarkKey);
1079 }
1080
1081 /**
cparsonsabeb8512018-06-11 12:44:06 -07001082 * Returns the declared provider (native and Skylark) for the specified constructor under the
1083 * specified attribute of this target in the BUILD file. May return null if there is no
1084 * TransitiveInfoCollection under the specified attribute.
1085 */
1086 @Nullable
cparsons4ebf6c02018-08-17 14:49:36 -07001087 public <T extends InfoInterface> T getPrerequisite(
cparsonsabeb8512018-06-11 12:44:06 -07001088 String attributeName, Mode mode, final BuiltinProvider<T> skylarkKey) {
1089 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
1090 return prerequisite == null ? null : prerequisite.get(skylarkKey);
1091 }
1092
1093
1094 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001095 * Returns all the providers of the specified type that are listed under the specified attribute
1096 * of this target in the BUILD file, and that contain the specified provider.
1097 */
1098 public <C extends TransitiveInfoProvider> Iterable<? extends TransitiveInfoCollection>
1099 getPrerequisitesIf(String attributeName, Mode mode, final Class<C> classType) {
1100 AnalysisUtils.checkProvider(classType);
1101 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
1102 }
1103
1104 /**
dslomov73527c32017-07-27 17:35:46 +02001105 * Returns all the providers of the specified type that are listed under the specified attribute
1106 * of this target in the BUILD file, and that contain the specified provider.
1107 */
dslomovde965ac2017-07-31 21:07:51 +02001108 public <C extends Info> Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
1109 String attributeName, Mode mode, final NativeProvider<C> classType) {
dslomov73527c32017-07-27 17:35:46 +02001110 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
1111 }
1112
dslomov73527c32017-07-27 17:35:46 +02001113 /**
Googler7ac77232019-06-04 14:26:47 -07001114 * Returns all the providers of the specified type that are listed under the specified attribute
1115 * of this target in the BUILD file, and that contain the specified provider.
1116 */
1117 public <C extends Info> Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
1118 String attributeName, Mode mode, final BuiltinProvider<C> classType) {
1119 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
1120 }
1121
1122 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001123 * Returns the prerequisite referred to by the specified attribute. Also checks whether
1124 * the attribute is marked as executable and that the target referred to can actually be
1125 * executed.
1126 *
1127 * <p>The {@code mode} argument must match the configuration transition specified in the
1128 * definition of the attribute.
1129 *
1130 * @param attributeName the name of the attribute
1131 * @param mode the configuration transition of the attribute
1132 *
1133 * @return the {@link FilesToRunProvider} interface of the prerequisite.
1134 */
Carmi Grushko802f39e2016-04-06 20:03:56 +00001135 @Nullable
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001136 public FilesToRunProvider getExecutablePrerequisite(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +00001137 Attribute ruleDefinition = attributes().getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001138
1139 if (ruleDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001140 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001141 + " is not defined");
1142 }
1143 if (!ruleDefinition.isExecutable()) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001144 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001145 + " is not configured to be executable");
1146 }
1147
1148 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
1149 if (prerequisite == null) {
1150 return null;
1151 }
1152
1153 FilesToRunProvider result = prerequisite.getProvider(FilesToRunProvider.class);
1154 if (result == null || result.getExecutable() == null) {
1155 attributeError(
1156 attributeName, prerequisite.getLabel() + " does not refer to a valid executable target");
1157 }
1158 return result;
1159 }
1160
ulfjack08ff9b82017-09-28 04:08:06 -04001161 public void initConfigurationMakeVariableContext(
1162 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
1163 Preconditions.checkState(configurationMakeVariableContext == null);
1164 configurationMakeVariableContext =
1165 new ConfigurationMakeVariableContext(
1166 this, getRule().getPackage(), getConfiguration(), makeVariableSuppliers);
1167 }
1168
1169 public void initConfigurationMakeVariableContext(MakeVariableSupplier... makeVariableSuppliers) {
1170 initConfigurationMakeVariableContext(ImmutableList.copyOf(makeVariableSuppliers));
1171 }
1172
ulfjack01bf32e2017-11-02 17:50:07 -04001173 public Expander getExpander(TemplateContext templateContext) {
1174 return new Expander(this, templateContext);
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001175 }
1176
ulfjack07860132017-09-29 08:59:44 -04001177 public Expander getExpander() {
1178 return new Expander(this, getConfigurationMakeVariableContext());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001179 }
1180
Googlera45a8e02019-05-13 11:17:02 -07001181 public Expander getExpander(ImmutableMap<Label, ImmutableCollection<Artifact>> labelMap) {
1182 return new Expander(this, getConfigurationMakeVariableContext(), labelMap);
1183 }
1184
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001185 /**
ulfjack08ff9b82017-09-28 04:08:06 -04001186 * Returns a cached context that maps Make variable names (string) to values (string) without any
1187 * extra {@link MakeVariableSupplier}.
hlopkoa4778052017-05-26 11:37:28 +02001188 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001189 public ConfigurationMakeVariableContext getConfigurationMakeVariableContext() {
1190 if (configurationMakeVariableContext == null) {
ulfjack08ff9b82017-09-28 04:08:06 -04001191 initConfigurationMakeVariableContext(ImmutableList.<MakeVariableSupplier>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001192 }
1193 return configurationMakeVariableContext;
1194 }
1195
John Cater13263f72017-05-24 19:06:47 +02001196 @Nullable
John Catercdfa9ca2019-04-05 12:32:09 -07001197 public ResolvedToolchainContext getToolchainContext() {
John Catereca28402017-05-17 21:44:12 +02001198 return toolchainContext;
1199 }
1200
gregce6acfe4e2018-05-25 08:38:39 -07001201 public ConstraintSemantics getConstraintSemantics() {
1202 return constraintSemantics;
1203 }
1204
John Cater15c90b32017-12-18 08:34:40 -08001205 @Override
1206 @Nullable
1207 public PlatformInfo getExecutionPlatform() {
1208 if (getToolchainContext() == null) {
1209 return null;
1210 }
John Caterc8bd74f2018-06-22 14:20:22 -07001211 return getToolchainContext().executionPlatform();
John Cater15c90b32017-12-18 08:34:40 -08001212 }
1213
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001214 private void checkAttribute(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +00001215 Attribute attributeDefinition = attributes.getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001216 if (attributeDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001217 throw new IllegalStateException(getRule().getLocation() + ": " + getRuleClassNameForLogging()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001218 + " attribute " + attributeName + " is not defined");
1219 }
Michael Staiba751f922017-02-14 15:50:04 +00001220 if (attributeDefinition.getType().getLabelClass() != LabelClass.DEPENDENCY) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001221 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001222 + " is not a label type attribute");
1223 }
John Cater2c0dece2019-04-02 09:18:18 -07001224 TransitionFactory<AttributeTransitionData> transitionFactory =
John Cater5adcd3e2019-03-28 10:14:32 -07001225 attributeDefinition.getTransitionFactory();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001226 if (mode == Mode.HOST) {
John Cater5adcd3e2019-03-28 10:14:32 -07001227 if (transitionFactory.isSplit()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001228 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001229 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001230 + " is not configured for the host configuration");
1231 }
1232 } else if (mode == Mode.TARGET) {
John Cater5adcd3e2019-03-28 10:14:32 -07001233 if (transitionFactory.isSplit() && !NoTransition.isInstance(transitionFactory)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001234 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001235 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001236 + " is not configured for the target configuration");
1237 }
1238 } else if (mode == Mode.DATA) {
gregce475d91a2018-05-25 12:18:27 -07001239 throw new IllegalStateException(getRule().getLocation() + ": "
1240 + getRuleClassNameForLogging() + " attribute " + attributeName
1241 + ": DATA transition no longer supported"); // See b/80157700.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001242 } else if (mode == Mode.SPLIT) {
jcatere8f5a982019-04-02 11:12:19 -07001243 if (!(attributeDefinition.getTransitionFactory().isSplit())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001244 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001245 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001246 + " is not configured for a split transition");
1247 }
1248 }
1249 }
1250
1251 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001252 * For the specified attribute "attributeName" (which must be of type
1253 * list(label)), resolve all the labels into ConfiguredTargets (for the
1254 * configuration appropriate to the attribute) and return their build
1255 * artifacts as a {@link PrerequisiteArtifacts} instance.
1256 *
1257 * @param attributeName the name of the attribute to traverse
1258 */
1259 public PrerequisiteArtifacts getPrerequisiteArtifacts(String attributeName, Mode mode) {
1260 return PrerequisiteArtifacts.get(this, attributeName, mode);
1261 }
1262
1263 /**
1264 * For the specified attribute "attributeName" (which must be of type label),
1265 * resolves the ConfiguredTarget and returns its single build artifact.
1266 *
1267 * <p>If the attribute is optional, has no default and was not specified, then
1268 * null will be returned. Note also that null is returned (and an attribute
1269 * error is raised) if there wasn't exactly one build artifact for the target.
1270 */
1271 public Artifact getPrerequisiteArtifact(String attributeName, Mode mode) {
1272 TransitiveInfoCollection target = getPrerequisite(attributeName, mode);
1273 return transitiveInfoCollectionToArtifact(attributeName, target);
1274 }
1275
1276 /**
1277 * Equivalent to getPrerequisiteArtifact(), but also asserts that
1278 * host-configuration is appropriate for the specified attribute.
1279 */
1280 public Artifact getHostPrerequisiteArtifact(String attributeName) {
1281 TransitiveInfoCollection target = getPrerequisite(attributeName, Mode.HOST);
1282 return transitiveInfoCollectionToArtifact(attributeName, target);
1283 }
1284
1285 private Artifact transitiveInfoCollectionToArtifact(
1286 String attributeName, TransitiveInfoCollection target) {
1287 if (target != null) {
1288 Iterable<Artifact> artifacts = target.getProvider(FileProvider.class).getFilesToBuild();
1289 if (Iterables.size(artifacts) == 1) {
1290 return Iterables.getOnlyElement(artifacts);
1291 } else {
1292 attributeError(attributeName, target.getLabel() + " expected a single artifact");
1293 }
1294 }
1295 return null;
1296 }
1297
1298 /**
1299 * Returns the sole file in the "srcs" attribute. Reports an error and
1300 * (possibly) returns null if "srcs" does not identify a single file of the
1301 * expected type.
1302 */
1303 public Artifact getSingleSource(String fileTypeName) {
1304 List<Artifact> srcs = PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list();
1305 switch (srcs.size()) {
1306 case 0 : // error already issued by getSrc()
1307 return null;
1308 case 1 : // ok
1309 return Iterables.getOnlyElement(srcs);
1310 default :
1311 attributeError("srcs", "only a single " + fileTypeName + " is allowed here");
1312 return srcs.get(0);
1313 }
1314 }
1315
1316 public Artifact getSingleSource() {
Michael Staib8824d5e2016-01-20 21:37:05 +00001317 return getSingleSource(getRuleClassNameForLogging() + " source file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001318 }
1319
1320 /**
1321 * Returns a path fragment qualified by the rule name and unique fragment to
1322 * disambiguate artifacts produced from the source file appearing in
1323 * multiple rules.
1324 *
1325 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1326 */
1327 public final PathFragment getUniqueDirectory(String fragment) {
nharmata5e924af2017-05-02 18:16:23 +02001328 return getUniqueDirectory(PathFragment.create(fragment));
1329 }
1330
1331 /**
1332 * Returns a path fragment qualified by the rule name and unique fragment to
1333 * disambiguate artifacts produced from the source file appearing in
1334 * multiple rules.
1335 *
1336 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1337 */
1338 public final PathFragment getUniqueDirectory(PathFragment fragment) {
1339 return AnalysisUtils.getUniqueDirectory(getLabel(), fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001340 }
1341
1342 /**
1343 * Check that all targets that were specified as sources are from the same
1344 * package as this rule. Output a warning or an error for every target that is
1345 * imported from a different package.
1346 */
1347 public void checkSrcsSamePackage(boolean onlyWarn) {
1348 PathFragment packageName = getLabel().getPackageFragment();
1349 for (Artifact srcItem : PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list()) {
1350 if (!srcItem.isSourceArtifact()) {
1351 // In theory, we should not do this check. However, in practice, we
1352 // have a couple of rules that do not obey the "srcs must contain
1353 // files and only files" rule. Thus, we are stuck with this hack here :(
1354 continue;
1355 }
1356 Label associatedLabel = srcItem.getOwner();
1357 PathFragment itemPackageName = associatedLabel.getPackageFragment();
1358 if (!itemPackageName.equals(packageName)) {
1359 String message = "please do not import '" + associatedLabel + "' directly. "
1360 + "You should either move the file to this package or depend on "
1361 + "an appropriate rule there";
1362 if (onlyWarn) {
1363 attributeWarning("srcs", message);
1364 } else {
1365 attributeError("srcs", message);
1366 }
1367 }
1368 }
1369 }
1370
1371
1372 /**
1373 * Returns the label to which the {@code NODEP_LABEL} attribute
1374 * {@code attrName} refers, checking that it is a valid label, and that it is
1375 * referring to a local target. Reports a warning otherwise.
1376 */
1377 public Label getLocalNodepLabelAttribute(String attrName) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001378 Label label = attributes().get(attrName, BuildType.NODEP_LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001379 if (label == null) {
1380 return null;
1381 }
1382
1383 if (!getTarget().getLabel().getPackageFragment().equals(label.getPackageFragment())) {
1384 attributeWarning(attrName, "does not reference a local rule");
1385 }
1386
1387 return label;
1388 }
1389
asteinb0de45462018-05-17 08:07:12 -07001390 @Override
Florian Weikert4b67d4f2015-09-14 13:35:34 +00001391 public Artifact getImplicitOutputArtifact(ImplicitOutputsFunction function)
1392 throws InterruptedException {
gregce11f3b0e2019-06-07 17:12:06 -07001393 return getImplicitOutputArtifact(function, /*contentBasedPath=*/ false);
1394 }
1395
1396 /**
1397 * Same as {@link #getImplicitOutputArtifact(ImplicitOutputsFunction)} but includes the option to
1398 * use a content-based path for this artifact (see {@link
1399 * BuildConfiguration#useContentBasedOutputPaths()}).
1400 */
1401 public Artifact getImplicitOutputArtifact(
1402 ImplicitOutputsFunction function, boolean contentBasedPath) throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001403 Iterable<String> result;
1404 try {
vladmos076977e2017-12-02 14:15:32 -08001405 result =
1406 function.getImplicitOutputs(
1407 getAnalysisEnvironment().getEventHandler(), RawAttributeMapper.of(rule));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001408 } catch (EvalException e) {
1409 // It's ok as long as we don't use this method from Skylark.
1410 throw new IllegalStateException(e);
1411 }
gregce11f3b0e2019-06-07 17:12:06 -07001412 return getImplicitOutputArtifact(Iterables.getOnlyElement(result), contentBasedPath);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001413 }
1414
1415 /**
1416 * Only use from Skylark. Returns the implicit output artifact for a given output path.
1417 */
1418 public Artifact getImplicitOutputArtifact(String path) {
gregce11f3b0e2019-06-07 17:12:06 -07001419 return getImplicitOutputArtifact(path, /*contentBasedPath=*/ false);
1420 }
1421
1422 /**
1423 * Same as {@link #getImplicitOutputArtifact(String)} but includes the option to use a a
1424 * content-based path for this artifact (see {@link
1425 * BuildConfiguration#useContentBasedOutputPaths()}).
1426 */
1427 private Artifact getImplicitOutputArtifact(String path, boolean contentBasedPath) {
1428 return getPackageRelativeArtifact(path, getBinOrGenfilesDirectory(), contentBasedPath);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001429 }
1430
1431 /**
1432 * Convenience method to return a host configured target for the "compiler"
1433 * attribute. Allows caller to decide whether a warning should be printed if
1434 * the "compiler" attribute is not set to the default value.
1435 *
1436 * @param warnIfNotDefault if true, print a warning if the value for the
1437 * "compiler" attribute is set to something other than the default
1438 * @return a ConfiguredTarget using the host configuration for the "compiler"
1439 * attribute
1440 */
1441 public final FilesToRunProvider getCompiler(boolean warnIfNotDefault) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001442 Label label = attributes().get("compiler", BuildType.LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001443 if (warnIfNotDefault && !label.equals(getRule().getAttrDefaultValue("compiler"))) {
1444 attributeWarning("compiler", "setting the compiler is strongly discouraged");
1445 }
1446 return getExecutablePrerequisite("compiler", Mode.HOST);
1447 }
1448
1449 /**
1450 * Returns the (unmodifiable, ordered) list of artifacts which are the outputs
1451 * of this target.
1452 *
1453 * <p>Each element in this list is associated with a single output, either
1454 * declared implicitly (via setImplicitOutputsFunction()) or explicitly
1455 * (listed in the 'outs' attribute of our rule).
1456 */
1457 public final ImmutableList<Artifact> getOutputArtifacts() {
1458 ImmutableList.Builder<Artifact> artifacts = ImmutableList.builder();
1459 for (OutputFile out : getRule().getOutputFiles()) {
1460 artifacts.add(createOutputArtifact(out));
1461 }
1462 return artifacts.build();
1463 }
1464
1465 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001466 * Like {@link #getOutputArtifacts()} but for a singular output item.
1467 * Reports an error if the "out" attribute is not a singleton.
1468 *
1469 * @return null if the output list is empty, the artifact for the first item
1470 * of the output list otherwise
1471 */
1472 public Artifact getOutputArtifact() {
1473 List<Artifact> outs = getOutputArtifacts();
1474 if (outs.size() != 1) {
1475 attributeError("out", "exactly one output file required");
1476 if (outs.isEmpty()) {
1477 return null;
1478 }
1479 }
1480 return outs.get(0);
1481 }
1482
plf727a07d2019-02-01 02:27:35 -08001483 @Override
janakr658d47f2019-05-29 11:11:30 -07001484 public final Artifact.DerivedArtifact getRelatedArtifact(
1485 PathFragment pathFragment, String extension) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001486 PathFragment file = FileSystemUtils.replaceExtension(pathFragment, extension);
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +00001487 return getDerivedArtifact(file, getConfiguration().getBinDirectory(rule.getRepository()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001488 }
1489
1490 /**
Googlerf812a2f2016-06-13 16:14:10 +00001491 * Returns true if the target for this context is a test target.
1492 */
1493 public boolean isTestTarget() {
1494 return TargetUtils.isTestRule(getTarget());
1495 }
1496
Googlercfdeb4d2018-02-08 07:13:33 -08001497 /** Returns true if the testonly attribute is set on this context. */
1498 public boolean isTestOnlyTarget() {
1499 return attributes().has("testonly", Type.BOOLEAN) && attributes().get("testonly", Type.BOOLEAN);
1500 }
1501
Googlerf812a2f2016-06-13 16:14:10 +00001502 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001503 * @return true if {@code rule} is visible from {@code prerequisite}.
1504 *
1505 * <p>This only computes the logic as implemented by the visibility system. The final decision
1506 * whether a dependency is allowed is made by
1507 * {@link ConfiguredRuleClassProvider.PrerequisiteValidator}.
1508 */
1509 public static boolean isVisible(Rule rule, TransitiveInfoCollection prerequisite) {
1510 // Check visibility attribute
cushon34ff85e2017-11-15 08:59:27 -08001511 for (PackageGroupContents specification :
1512 prerequisite.getProvider(VisibilityProvider.class).getVisibility()) {
Lukacs Berki485eb962016-01-13 10:47:29 +00001513 if (specification.containsPackage(rule.getLabel().getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001514 return true;
1515 }
1516 }
1517
1518 return false;
1519 }
1520
1521 /**
1522 * @return the set of features applicable for the current rule's package.
1523 */
1524 public ImmutableSet<String> getFeatures() {
Googler993f1de2018-02-20 02:31:10 -08001525 return enabledFeatures;
1526 }
1527
1528 /** @return the set of features that are disabled for the current rule's package. */
1529 public ImmutableSet<String> getDisabledFeatures() {
1530 return disabledFeatures;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001531 }
1532
Florian Weikertb8a6a942015-09-25 12:36:08 +00001533 @Override
plf43109892019-02-12 05:45:05 -08001534 public RuleErrorConsumer getRuleErrorConsumer() {
1535 return this;
1536 }
1537
1538 @Override
Florian Weikertb8a6a942015-09-25 12:36:08 +00001539 public String toString() {
1540 return "RuleContext(" + getLabel() + ", " + getConfiguration() + ")";
1541 }
1542
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001543 /**
1544 * Builder class for a RuleContext.
1545 */
Florian Weikertb8a6a942015-09-25 12:36:08 +00001546 public static final class Builder implements RuleErrorConsumer {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001547 private final AnalysisEnvironment env;
lpino5fe7ed02018-07-18 05:55:23 -07001548 private final Target target;
Michael Staibb51251e2015-09-29 23:31:51 +00001549 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
lberki78651d42018-04-06 01:52:58 -07001550 private ImmutableList<Class<? extends BuildConfiguration.Fragment>> universalFragments;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001551 private final BuildConfiguration configuration;
Greg Estren9eb1cf02015-06-26 22:18:35 +00001552 private final BuildConfiguration hostConfiguration;
janakreaff19c2019-01-31 13:59:40 -08001553 private final ActionLookupValue.ActionLookupKey actionOwnerSymbol;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001554 private final PrerequisiteValidator prerequisiteValidator;
cparsonse8d450c2018-10-04 16:01:53 -07001555 private final RuleErrorConsumer reporter;
janakr9c101402018-03-10 06:48:59 -08001556 private OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap;
Lukacs Berki7894c182016-05-10 12:07:01 +00001557 private ImmutableMap<Label, ConfigMatchingProvider> configConditions;
cushon34ff85e2017-11-15 08:59:27 -08001558 private NestedSet<PackageGroupContents> visibility;
Dmitry Lomovace678e2015-12-16 15:10:20 +00001559 private ImmutableMap<String, Attribute> aspectAttributes;
dslomov44d15712017-12-20 05:42:28 -08001560 private ImmutableList<Aspect> aspects;
John Catercdfa9ca2019-04-05 12:32:09 -07001561 private ResolvedToolchainContext toolchainContext;
gregce6acfe4e2018-05-25 08:38:39 -07001562 private ConstraintSemantics constraintSemantics;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001563
ulfjack865b6212018-06-14 03:41:55 -07001564 @VisibleForTesting
1565 public Builder(
Michael Staib8824d5e2016-01-20 21:37:05 +00001566 AnalysisEnvironment env,
lpino5fe7ed02018-07-18 05:55:23 -07001567 Target target,
dslomov44d15712017-12-20 05:42:28 -08001568 ImmutableList<Aspect> aspects,
Michael Staib8824d5e2016-01-20 21:37:05 +00001569 BuildConfiguration configuration,
Greg Estren9eb1cf02015-06-26 22:18:35 +00001570 BuildConfiguration hostConfiguration,
Michael Staib8824d5e2016-01-20 21:37:05 +00001571 PrerequisiteValidator prerequisiteValidator,
janakreaff19c2019-01-31 13:59:40 -08001572 ConfigurationFragmentPolicy configurationFragmentPolicy,
1573 ActionLookupValue.ActionLookupKey actionOwnerSymbol) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001574 this.env = Preconditions.checkNotNull(env);
lpino5fe7ed02018-07-18 05:55:23 -07001575 this.target = Preconditions.checkNotNull(target);
dslomov44d15712017-12-20 05:42:28 -08001576 this.aspects = aspects;
Michael Staib8824d5e2016-01-20 21:37:05 +00001577 this.configurationFragmentPolicy = Preconditions.checkNotNull(configurationFragmentPolicy);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001578 this.configuration = Preconditions.checkNotNull(configuration);
Greg Estren9eb1cf02015-06-26 22:18:35 +00001579 this.hostConfiguration = Preconditions.checkNotNull(hostConfiguration);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001580 this.prerequisiteValidator = prerequisiteValidator;
janakreaff19c2019-01-31 13:59:40 -08001581 this.actionOwnerSymbol = Preconditions.checkNotNull(actionOwnerSymbol);
cparsonse8d450c2018-10-04 16:01:53 -07001582 if (configuration.allowAnalysisFailures()) {
1583 reporter = new SuppressingErrorReporter();
1584 } else {
1585 reporter = new ErrorReporter(env, target.getAssociatedRule(), getRuleClassNameForLogging());
1586 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001587 }
1588
ulfjack865b6212018-06-14 03:41:55 -07001589 @VisibleForTesting
1590 public RuleContext build() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001591 Preconditions.checkNotNull(prerequisiteMap);
1592 Preconditions.checkNotNull(configConditions);
1593 Preconditions.checkNotNull(visibility);
gregce6acfe4e2018-05-25 08:38:39 -07001594 Preconditions.checkNotNull(constraintSemantics);
lpino5fe7ed02018-07-18 05:55:23 -07001595 AttributeMap attributes =
1596 ConfiguredAttributeMapper.of(target.getAssociatedRule(), configConditions);
Nathan Harmatafcb17112016-04-13 16:56:58 +00001597 validateAttributes(attributes);
janakr9c101402018-03-10 06:48:59 -08001598 ListMultimap<String, ConfiguredTargetAndData> targetMap = createTargetMap();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001599 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap =
lpino5fe7ed02018-07-18 05:55:23 -07001600 createFilesetEntryMap(target.getAssociatedRule(), configConditions);
Michael Staib8824d5e2016-01-20 21:37:05 +00001601 return new RuleContext(
1602 this,
Nathan Harmatafcb17112016-04-13 16:56:58 +00001603 attributes,
Michael Staib8824d5e2016-01-20 21:37:05 +00001604 targetMap,
1605 filesetEntryMap,
1606 configConditions,
lberki78651d42018-04-06 01:52:58 -07001607 universalFragments,
Michael Staib8824d5e2016-01-20 21:37:05 +00001608 getRuleClassNameForLogging(),
janakreaff19c2019-01-31 13:59:40 -08001609 actionOwnerSymbol,
John Cater13263f72017-05-24 19:06:47 +02001610 aspectAttributes != null ? aspectAttributes : ImmutableMap.<String, Attribute>of(),
gregce6acfe4e2018-05-25 08:38:39 -07001611 toolchainContext,
1612 constraintSemantics);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001613 }
1614
Nathan Harmatafcb17112016-04-13 16:56:58 +00001615 private void validateAttributes(AttributeMap attributes) {
lpino5fe7ed02018-07-18 05:55:23 -07001616 target
1617 .getAssociatedRule()
1618 .getRuleClassObject()
michajloc1062a42018-09-26 14:53:38 -07001619 .checkAttributesNonEmpty(reporter, attributes);
Nathan Harmatafcb17112016-04-13 16:56:58 +00001620 }
1621
ulfjack865b6212018-06-14 03:41:55 -07001622 public Builder setVisibility(NestedSet<PackageGroupContents> visibility) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001623 this.visibility = visibility;
1624 return this;
1625 }
1626
1627 /**
1628 * Sets the prerequisites and checks their visibility. It also generates appropriate error or
1629 * warning messages and sets the error flag as appropriate.
1630 */
ulfjack865b6212018-06-14 03:41:55 -07001631 public Builder setPrerequisites(
janakr9c101402018-03-10 06:48:59 -08001632 OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001633 this.prerequisiteMap = Preconditions.checkNotNull(prerequisiteMap);
1634 return this;
1635 }
1636
1637 /**
Carmi Grushko06f65f72015-11-02 22:42:24 +00001638 * Adds attributes which are defined by an Aspect (and not by RuleClass).
1639 */
ulfjack865b6212018-06-14 03:41:55 -07001640 public Builder setAspectAttributes(Map<String, Attribute> aspectAttributes) {
Dmitry Lomovace678e2015-12-16 15:10:20 +00001641 this.aspectAttributes = ImmutableMap.copyOf(aspectAttributes);
Carmi Grushko06f65f72015-11-02 22:42:24 +00001642 return this;
1643 }
1644
1645 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001646 * Sets the configuration conditions needed to determine which paths to follow for this
1647 * rule's configurable attributes.
1648 */
ulfjack865b6212018-06-14 03:41:55 -07001649 public Builder setConfigConditions(
1650 ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001651 this.configConditions = Preconditions.checkNotNull(configConditions);
1652 return this;
1653 }
1654
Greg Estrenc5a352f2015-11-13 17:25:36 +00001655 /**
1656 * Sets the fragment that can be legally accessed even when not explicitly declared.
1657 */
ulfjack865b6212018-06-14 03:41:55 -07001658 public Builder setUniversalFragments(
lberki78651d42018-04-06 01:52:58 -07001659 ImmutableList<Class<? extends BuildConfiguration.Fragment>> fragments) {
Greg Estrenc5a352f2015-11-13 17:25:36 +00001660 // TODO(bazel-team): Add this directly to ConfigurationFragmentPolicy, so we
1661 // don't need separate logic specifically for checking this fragment. The challenge is
1662 // that we need RuleClassProvider to figure out what this fragment is, and not every
1663 // call state that creates ConfigurationFragmentPolicy has access to that.
lberki78651d42018-04-06 01:52:58 -07001664 this.universalFragments = fragments;
Greg Estrenc5a352f2015-11-13 17:25:36 +00001665 return this;
1666 }
1667
John Catercdfa9ca2019-04-05 12:32:09 -07001668 /** Sets the {@link ResolvedToolchainContext} used to access toolchains used by this rule. */
1669 public Builder setToolchainContext(ResolvedToolchainContext toolchainContext) {
John Cater13263f72017-05-24 19:06:47 +02001670 this.toolchainContext = toolchainContext;
1671 return this;
1672 }
1673
ulfjack865b6212018-06-14 03:41:55 -07001674 public Builder setConstraintSemantics(ConstraintSemantics constraintSemantics) {
gregce6acfe4e2018-05-25 08:38:39 -07001675 this.constraintSemantics = constraintSemantics;
1676 return this;
1677 }
1678
janakr9c101402018-03-10 06:48:59 -08001679 private boolean validateFilesetEntry(FilesetEntry filesetEntry, ConfiguredTargetAndData src) {
felly2b3befd2018-08-10 10:37:56 -07001680 NestedSet<Artifact> filesToBuild =
1681 src.getConfiguredTarget().getProvider(FileProvider.class).getFilesToBuild();
1682 if (filesToBuild.isSingleton() && Iterables.getOnlyElement(filesToBuild).isFileset()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001683 return true;
1684 }
felly2b3befd2018-08-10 10:37:56 -07001685
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001686 if (filesetEntry.isSourceFileset()) {
1687 return true;
1688 }
1689
1690 Target srcTarget = src.getTarget();
1691 if (!(srcTarget instanceof FileTarget)) {
1692 attributeError("entries", String.format(
1693 "Invalid 'srcdir' target '%s'. Must be another Fileset or package",
1694 srcTarget.getLabel()));
1695 return false;
1696 }
1697
1698 if (srcTarget instanceof OutputFile) {
1699 attributeWarning("entries", String.format("'srcdir' target '%s' is not an input file. "
1700 + "This forces the Fileset to be executed unconditionally",
1701 srcTarget.getLabel()));
1702 }
1703
1704 return true;
1705 }
1706
1707 /**
1708 * Determines and returns a map from attribute name to list of configured fileset entries, based
1709 * on a PrerequisiteMap instance.
1710 */
1711 private ListMultimap<String, ConfiguredFilesetEntry> createFilesetEntryMap(
Lukacs Berki7894c182016-05-10 12:07:01 +00001712 final Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
lpino5fe7ed02018-07-18 05:55:23 -07001713 if (!target.getTargetKind().equals("Fileset rule")) {
1714 return ImmutableSortedKeyListMultimap.<String, ConfiguredFilesetEntry>builder().build();
1715 }
1716
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001717 final ImmutableSortedKeyListMultimap.Builder<String, ConfiguredFilesetEntry> mapBuilder =
1718 ImmutableSortedKeyListMultimap.builder();
1719 for (Attribute attr : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001720 if (attr.getType() != BuildType.FILESET_ENTRY_LIST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001721 continue;
1722 }
1723 String attributeName = attr.getName();
janakr9c101402018-03-10 06:48:59 -08001724 Map<Label, ConfiguredTargetAndData> ctMap = new HashMap<>();
1725 for (ConfiguredTargetAndData prerequisite : prerequisiteMap.get(attr)) {
janakrf3e6f252018-01-18 07:45:12 -08001726 ctMap.put(
1727 AliasProvider.getDependencyLabel(prerequisite.getConfiguredTarget()), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001728 }
1729 List<FilesetEntry> entries = ConfiguredAttributeMapper.of(rule, configConditions)
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001730 .get(attributeName, BuildType.FILESET_ENTRY_LIST);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001731 for (FilesetEntry entry : entries) {
1732 if (entry.getFiles() == null) {
1733 Label label = entry.getSrcLabel();
janakr9c101402018-03-10 06:48:59 -08001734 ConfiguredTargetAndData src = ctMap.get(label);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001735 if (!validateFilesetEntry(entry, src)) {
1736 continue;
1737 }
1738
janakrf3e6f252018-01-18 07:45:12 -08001739 mapBuilder.put(
1740 attributeName, new ConfiguredFilesetEntry(entry, src.getConfiguredTarget()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001741 } else {
1742 ImmutableList.Builder<TransitiveInfoCollection> files = ImmutableList.builder();
1743 for (Label file : entry.getFiles()) {
janakrf3e6f252018-01-18 07:45:12 -08001744 files.add(ctMap.get(file).getConfiguredTarget());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001745 }
1746 mapBuilder.put(attributeName, new ConfiguredFilesetEntry(entry, files.build()));
1747 }
1748 }
1749 }
1750 return mapBuilder.build();
1751 }
1752
janakrf3e6f252018-01-18 07:45:12 -08001753 /** Determines and returns a map from attribute name to list of configured targets. */
janakr9c101402018-03-10 06:48:59 -08001754 private ImmutableSortedKeyListMultimap<String, ConfiguredTargetAndData> createTargetMap() {
1755 ImmutableSortedKeyListMultimap.Builder<String, ConfiguredTargetAndData> mapBuilder =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001756 ImmutableSortedKeyListMultimap.builder();
1757
janakr9c101402018-03-10 06:48:59 -08001758 for (Map.Entry<Attribute, Collection<ConfiguredTargetAndData>> entry :
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001759 prerequisiteMap.asMap().entrySet()) {
1760 Attribute attribute = entry.getKey();
1761 if (attribute == null) {
1762 continue;
1763 }
lberki1cd6d1e2017-06-14 16:20:19 +02001764
1765 if (attribute.isSingleArtifact() && entry.getValue().size() > 1) {
1766 attributeError(attribute.getName(), "must contain a single dependency");
1767 continue;
1768 }
1769
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001770 if (attribute.isSilentRuleClassFilter()) {
1771 Predicate<RuleClass> filter = attribute.getAllowedRuleClassesPredicate();
janakr9c101402018-03-10 06:48:59 -08001772 for (ConfiguredTargetAndData configuredTarget : entry.getValue()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001773 Target prerequisiteTarget = configuredTarget.getTarget();
1774 if ((prerequisiteTarget instanceof Rule)
1775 && filter.apply(((Rule) prerequisiteTarget).getRuleClassObject())) {
1776 validateDirectPrerequisite(attribute, configuredTarget);
1777 mapBuilder.put(attribute.getName(), configuredTarget);
1778 }
1779 }
1780 } else {
janakr9c101402018-03-10 06:48:59 -08001781 for (ConfiguredTargetAndData configuredTarget : entry.getValue()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001782 validateDirectPrerequisite(attribute, configuredTarget);
1783 mapBuilder.put(attribute.getName(), configuredTarget);
1784 }
1785 }
1786 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001787 return mapBuilder.build();
1788 }
1789
cparsons963881a2018-10-03 14:23:55 -07001790 /**
1791 * Post a raw event to the analysis environment's event handler. This circumvents normal
1792 * error and warning reporting functionality to post events, and should only be used
1793 * in rare cases where a custom event needs to be handled.
1794 */
Klaus Aehlig16a107d2017-05-31 18:02:43 +02001795 public void post(Postable event) {
cparsons963881a2018-10-03 14:23:55 -07001796 env.getEventHandler().post(event);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001797 }
1798
Florian Weikertb8a6a942015-09-25 12:36:08 +00001799 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001800 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001801 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001802 }
1803
Florian Weikertb8a6a942015-09-25 12:36:08 +00001804 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001805 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001806 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001807 }
1808
Florian Weikertb8a6a942015-09-25 12:36:08 +00001809 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001810 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001811 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001812 }
1813
Florian Weikertb8a6a942015-09-25 12:36:08 +00001814 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001815 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001816 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001817 }
1818
cparsons0dcffc52017-10-13 23:40:31 +02001819 @Override
cparsons0dcffc52017-10-13 23:40:31 +02001820 public boolean hasErrors() {
1821 return reporter.hasErrors();
1822 }
1823
janakrf3e6f252018-01-18 07:45:12 -08001824 private String badPrerequisiteMessage(
lberkiee2dcae2018-03-28 05:49:04 -07001825 ConfiguredTargetAndData prerequisite, String reason, boolean isWarning) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001826 String msgReason = reason != null ? " (" + reason + ")" : "";
1827 if (isWarning) {
Googlere49cd592016-07-29 19:32:38 +00001828 return String.format(
lberkiee2dcae2018-03-28 05:49:04 -07001829 "%s is unexpected here%s; continuing anyway",
1830 AliasProvider.describeTargetWithAliases(prerequisite, TargetMode.WITH_KIND),
Googlere49cd592016-07-29 19:32:38 +00001831 msgReason);
1832 }
lberkiee2dcae2018-03-28 05:49:04 -07001833 return String.format("%s is misplaced here%s",
1834 AliasProvider.describeTargetWithAliases(prerequisite, TargetMode.WITH_KIND), msgReason);
Googlere49cd592016-07-29 19:32:38 +00001835 }
1836
janakrf3e6f252018-01-18 07:45:12 -08001837 private void reportBadPrerequisite(
1838 Attribute attribute,
janakr9c101402018-03-10 06:48:59 -08001839 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08001840 String reason,
1841 boolean isWarning) {
lberkiee2dcae2018-03-28 05:49:04 -07001842 String message = badPrerequisiteMessage(prerequisite, reason, isWarning);
Googlere49cd592016-07-29 19:32:38 +00001843 if (isWarning) {
1844 attributeWarning(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001845 } else {
Googlere49cd592016-07-29 19:32:38 +00001846 attributeError(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001847 }
1848 }
1849
janakrf3e6f252018-01-18 07:45:12 -08001850 private void validateDirectPrerequisiteType(
janakr9c101402018-03-10 06:48:59 -08001851 ConfiguredTargetAndData prerequisite, Attribute attribute) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001852 Target prerequisiteTarget = prerequisite.getTarget();
1853 Label prerequisiteLabel = prerequisiteTarget.getLabel();
1854
1855 if (prerequisiteTarget instanceof Rule) {
1856 Rule prerequisiteRule = (Rule) prerequisiteTarget;
1857
lpino5fe7ed02018-07-18 05:55:23 -07001858 String reason =
1859 attribute
1860 .getValidityPredicate()
1861 .checkValid(target.getAssociatedRule(), prerequisiteRule);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001862 if (reason != null) {
lberkiee2dcae2018-03-28 05:49:04 -07001863 reportBadPrerequisite(attribute, prerequisite, reason, false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001864 }
1865 }
1866
Yun Pengefd7ca12016-03-03 13:14:38 +00001867 if (prerequisiteTarget instanceof Rule) {
1868 validateRuleDependency(prerequisite, attribute);
1869 } else if (prerequisiteTarget instanceof FileTarget) {
1870 if (attribute.isStrictLabelCheckingEnabled()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001871 if (!attribute.getAllowedFileTypesPredicate()
1872 .apply(((FileTarget) prerequisiteTarget).getFilename())) {
1873 if (prerequisiteTarget instanceof InputFile
1874 && !((InputFile) prerequisiteTarget).getPath().exists()) {
1875 // Misplaced labels, no corresponding target exists
1876 if (attribute.getAllowedFileTypesPredicate().isNone()
1877 && !((InputFile) prerequisiteTarget).getFilename().contains(".")) {
1878 // There are no allowed files in the attribute but it's not a valid rule,
1879 // and the filename doesn't contain a dot --> probably a misspelled rule
1880 attributeError(attribute.getName(),
1881 "rule '" + prerequisiteLabel + "' does not exist");
1882 } else {
1883 attributeError(attribute.getName(),
1884 "target '" + prerequisiteLabel + "' does not exist");
1885 }
1886 } else {
1887 // The file exists but has a bad extension
lberkiee2dcae2018-03-28 05:49:04 -07001888 reportBadPrerequisite(attribute, prerequisite,
Ulf Adams07dba942015-03-05 14:47:37 +00001889 "expected " + attribute.getAllowedFileTypesPredicate(), false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001890 }
1891 }
1892 }
1893 }
1894 }
1895
Michael Staib2707a882016-09-16 21:06:40 +00001896 /** Returns whether the context being constructed is for the evaluation of an aspect. */
1897 public boolean forAspect() {
dslomov44d15712017-12-20 05:42:28 -08001898 return !aspects.isEmpty();
Michael Staib2707a882016-09-16 21:06:40 +00001899 }
1900
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001901 public Rule getRule() {
lpino5fe7ed02018-07-18 05:55:23 -07001902 return target.getAssociatedRule();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001903 }
1904
Michael Staib8824d5e2016-01-20 21:37:05 +00001905 /**
1906 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
1907 */
1908 public String getRuleClassNameForLogging() {
dslomov44d15712017-12-20 05:42:28 -08001909 if (aspects.isEmpty()) {
lpino5fe7ed02018-07-18 05:55:23 -07001910 return target.getAssociatedRule().getRuleClass();
Dmitry Lomov15756522016-12-16 16:52:37 +00001911 }
1912
dslomov44d15712017-12-20 05:42:28 -08001913 return Joiner.on(",")
1914 .join(aspects.stream().map(a -> a.getDescriptor()).collect(Collectors.toList()))
1915 + " aspect on "
lpino5fe7ed02018-07-18 05:55:23 -07001916 + target.getAssociatedRule().getRuleClass();
Michael Staib8824d5e2016-01-20 21:37:05 +00001917 }
1918
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001919 public BuildConfiguration getConfiguration() {
1920 return configuration;
1921 }
1922
1923 /**
1924 * @return true if {@code rule} is visible from {@code prerequisite}.
1925 *
1926 * <p>This only computes the logic as implemented by the visibility system. The final decision
1927 * whether a dependency is allowed is made by
1928 * {@link ConfiguredRuleClassProvider.PrerequisiteValidator}, who is supposed to call this
1929 * method to determine whether a dependency is allowed as per visibility rules.
1930 */
1931 public boolean isVisible(TransitiveInfoCollection prerequisite) {
lpino5fe7ed02018-07-18 05:55:23 -07001932 return RuleContext.isVisible(target.getAssociatedRule(), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001933 }
1934
janakrf3e6f252018-01-18 07:45:12 -08001935 private void validateDirectPrerequisiteFileTypes(
janakr9c101402018-03-10 06:48:59 -08001936 ConfiguredTargetAndData prerequisite, Attribute attribute) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001937 if (attribute.isSkipAnalysisTimeFileTypeCheck()) {
1938 return;
1939 }
1940 FileTypeSet allowedFileTypes = attribute.getAllowedFileTypesPredicate();
Ulf Adams788fd1a2015-03-12 13:54:09 +00001941 if (allowedFileTypes == null) {
1942 // It's not a label or label_list attribute.
1943 return;
1944 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001945 if (allowedFileTypes == FileTypeSet.ANY_FILE && !attribute.isNonEmpty()
1946 && !attribute.isSingleArtifact()) {
1947 return;
1948 }
1949
1950 // If we allow any file we still need to check if there are actually files generated
1951 // Note that this check only runs for ANY_FILE predicates if the attribute is NON_EMPTY
1952 // or SINGLE_ARTIFACT
1953 // If we performed this check when allowedFileTypes == NO_FILE this would
1954 // always throw an error in those cases
1955 if (allowedFileTypes != FileTypeSet.NO_FILE) {
janakrf3e6f252018-01-18 07:45:12 -08001956 Iterable<Artifact> artifacts =
1957 prerequisite.getConfiguredTarget().getProvider(FileProvider.class).getFilesToBuild();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001958 if (attribute.isSingleArtifact() && Iterables.size(artifacts) != 1) {
janakrf3e6f252018-01-18 07:45:12 -08001959 attributeError(
1960 attribute.getName(),
1961 "'" + prerequisite.getTarget().getLabel() + "' must produce a single file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001962 return;
1963 }
1964 for (Artifact sourceArtifact : artifacts) {
1965 if (allowedFileTypes.apply(sourceArtifact.getFilename())) {
1966 return;
1967 }
Googler2d90b6a2018-07-26 12:37:34 -07001968 if (sourceArtifact.isTreeArtifact()) {
1969 return;
1970 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001971 }
janakrf3e6f252018-01-18 07:45:12 -08001972 attributeError(
1973 attribute.getName(),
1974 "'"
1975 + prerequisite.getTarget().getLabel()
1976 + "' does not produce any "
1977 + getRuleClassNameForLogging()
1978 + " "
1979 + attribute.getName()
1980 + " files (expected "
1981 + allowedFileTypes
1982 + ")");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001983 }
1984 }
1985
dslomov7df85152017-08-01 20:47:59 +02001986 /**
dslomovc13bb392017-08-02 23:29:54 +02001987 * Because some rules still have to use allowedRuleClasses to do rule dependency validation. A
1988 * dependency is valid if it is from a rule in allowedRuledClasses, OR if all of the providers
1989 * in requiredProviders are provided by the target.
dslomov7df85152017-08-01 20:47:59 +02001990 */
janakr9c101402018-03-10 06:48:59 -08001991 private void validateRuleDependency(ConfiguredTargetAndData prerequisite, Attribute attribute) {
dslomov7df85152017-08-01 20:47:59 +02001992
dslomovc13bb392017-08-02 23:29:54 +02001993 Set<String> unfulfilledRequirements = new LinkedHashSet<>();
1994 if (checkRuleDependencyClass(prerequisite, attribute, unfulfilledRequirements)) {
1995 return;
1996 }
1997
1998 if (checkRuleDependencyClassWarnings(prerequisite, attribute)) {
1999 return;
2000 }
2001
2002 if (checkRuleDependencyMandatoryProviders(prerequisite, attribute, unfulfilledRequirements)) {
2003 return;
2004 }
2005
2006 // not allowed rule class and some mandatory providers missing => reject.
2007 if (!unfulfilledRequirements.isEmpty()) {
2008 attributeError(
2009 attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
2010 }
2011 }
2012
2013 /** Check if prerequisite should be allowed based on its rule class. */
2014 private boolean checkRuleDependencyClass(
janakr9c101402018-03-10 06:48:59 -08002015 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08002016 Attribute attribute,
2017 Set<String> unfulfilledRequirements) {
dslomovc32e1b12017-07-31 19:23:52 +02002018 if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
dslomovc13bb392017-08-02 23:29:54 +02002019 if (attribute
2020 .getAllowedRuleClassesPredicate()
2021 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002022 // prerequisite has an allowed rule class => accept.
dslomovc13bb392017-08-02 23:29:54 +02002023 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002024 }
2025 // remember that the rule class that was not allowed;
2026 // but maybe prerequisite provides required providers? do not reject yet.
dslomovc13bb392017-08-02 23:29:54 +02002027 unfulfilledRequirements.add(
dslomovc32e1b12017-07-31 19:23:52 +02002028 badPrerequisiteMessage(
dslomovc32e1b12017-07-31 19:23:52 +02002029 prerequisite,
2030 "expected " + attribute.getAllowedRuleClassesPredicate(),
dslomovc13bb392017-08-02 23:29:54 +02002031 false));
dslomovc32e1b12017-07-31 19:23:52 +02002032 }
dslomovc13bb392017-08-02 23:29:54 +02002033 return false;
2034 }
dslomovc32e1b12017-07-31 19:23:52 +02002035
dslomovc13bb392017-08-02 23:29:54 +02002036 /**
2037 * Check if prerequisite should be allowed with warning based on its rule class.
2038 *
2039 * <p>If yes, also issues said warning.
2040 */
2041 private boolean checkRuleDependencyClassWarnings(
janakr9c101402018-03-10 06:48:59 -08002042 ConfiguredTargetAndData prerequisite, Attribute attribute) {
dslomovc13bb392017-08-02 23:29:54 +02002043 if (attribute
2044 .getAllowedRuleClassesWarningPredicate()
2045 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002046 Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate();
dslomovc13bb392017-08-02 23:29:54 +02002047 reportBadPrerequisite(
2048 attribute,
dslomovc13bb392017-08-02 23:29:54 +02002049 prerequisite,
dslomovc32e1b12017-07-31 19:23:52 +02002050 allowedRuleClasses == Predicates.<RuleClass>alwaysTrue()
dslomovde965ac2017-07-31 21:07:51 +02002051 ? null
2052 : "expected " + allowedRuleClasses,
dslomovc32e1b12017-07-31 19:23:52 +02002053 true);
2054 // prerequisite has a rule class allowed with a warning => accept, emitting a warning.
dslomovc13bb392017-08-02 23:29:54 +02002055 return true;
2056 }
2057 return false;
2058 }
2059
2060 /** Check if prerequisite should be allowed based on required providers on the attribute. */
2061 private boolean checkRuleDependencyMandatoryProviders(
janakr9c101402018-03-10 06:48:59 -08002062 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08002063 Attribute attribute,
2064 Set<String> unfulfilledRequirements) {
dslomovc13bb392017-08-02 23:29:54 +02002065 RequiredProviders requiredProviders = attribute.getRequiredProviders();
2066
2067 if (requiredProviders.acceptsAny()) {
2068 // If no required providers specified, we do not know if we should accept.
2069 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002070 }
2071
janakrf3e6f252018-01-18 07:45:12 -08002072 if (prerequisite.getConfiguredTarget().satisfies(requiredProviders)) {
dslomovc13bb392017-08-02 23:29:54 +02002073 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002074 }
2075
dslomovc13bb392017-08-02 23:29:54 +02002076 unfulfilledRequirements.add(
2077 String.format(
2078 "'%s' does not have mandatory providers: %s",
janakrf3e6f252018-01-18 07:45:12 -08002079 prerequisite.getTarget().getLabel(),
2080 prerequisite
2081 .getConfiguredTarget()
2082 .missingProviders(requiredProviders)
2083 .getDescription()));
dslomovc32e1b12017-07-31 19:23:52 +02002084
dslomovc13bb392017-08-02 23:29:54 +02002085 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002086 }
2087
janakrf3e6f252018-01-18 07:45:12 -08002088 private void validateDirectPrerequisite(
janakr9c101402018-03-10 06:48:59 -08002089 Attribute attribute, ConfiguredTargetAndData prerequisite) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002090 validateDirectPrerequisiteType(prerequisite, attribute);
2091 validateDirectPrerequisiteFileTypes(prerequisite, attribute);
Greg Estren875c7a72015-09-24 19:57:54 +00002092 if (attribute.performPrereqValidatorCheck()) {
Ulf Adams0b638972015-09-08 13:25:35 +00002093 prerequisiteValidator.validate(this, prerequisite, attribute);
2094 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002095 }
2096 }
2097
ruperts8986b6e2017-10-17 00:26:29 +02002098 /** Helper class for reporting errors and warnings. */
cparsons963881a2018-10-03 14:23:55 -07002099 private static final class ErrorReporter extends EventHandlingErrorReporter
ruperts8986b6e2017-10-17 00:26:29 +02002100 implements RuleErrorConsumer {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002101 private final Rule rule;
2102
Michael Staib8824d5e2016-01-20 21:37:05 +00002103 ErrorReporter(AnalysisEnvironment env, Rule rule, String ruleClassNameForLogging) {
asteinbb82db782018-05-18 08:21:39 -07002104 super(ruleClassNameForLogging, env);
Florian Weikertb8a6a942015-09-25 12:36:08 +00002105 this.rule = rule;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002106 }
2107
2108 @Override
asteinbb82db782018-05-18 08:21:39 -07002109 protected String getMacroMessageAppendix(String attrName) {
2110 return rule.wasCreatedByMacro()
2111 ? String.format(
2112 ". Since this rule was created by the macro '%s', the error might have been "
Florian Weikertb8a6a942015-09-25 12:36:08 +00002113 + "caused by the macro implementation in %s",
asteinbb82db782018-05-18 08:21:39 -07002114 getGeneratorFunction(), rule.getAttributeLocationWithoutMacro(attrName))
2115 : "";
Florian Weikertb8a6a942015-09-25 12:36:08 +00002116 }
2117
Florian Weikertb8a6a942015-09-25 12:36:08 +00002118 private String getGeneratorFunction() {
2119 return (String) rule.getAttributeContainer().getAttr("generator_function");
2120 }
asteinbb82db782018-05-18 08:21:39 -07002121
2122 @Override
2123 protected Label getLabel() {
2124 return rule.getLabel();
2125 }
2126
2127 @Override
2128 protected Location getRuleLocation() {
2129 return rule.getLocation();
2130 }
2131
2132 @Override
2133 protected Location getAttributeLocation(String attrName) {
2134 return rule.getAttributeLocation(attrName);
2135 }
cparsonse8d450c2018-10-04 16:01:53 -07002136 }
asteinbb82db782018-05-18 08:21:39 -07002137
cparsonse8d450c2018-10-04 16:01:53 -07002138 /**
2139 * Implementation of an error consumer which does not post any events, saves rule and attribute
2140 * errors for future consumption, and drops warnings.
2141 */
2142 public static final class SuppressingErrorReporter implements RuleErrorConsumer {
2143 private final List<String> errorMessages = Lists.newArrayList();
2144
2145 @Override
2146 public void ruleWarning(String message) {}
2147
2148 @Override
2149 public void ruleError(String message) {
2150 errorMessages.add(message);
2151 }
2152
2153 @Override
2154 public void attributeWarning(String attrName, String message) {}
2155
2156 @Override
2157 public void attributeError(String attrName, String message) {
2158 errorMessages.add(message);
2159 }
2160
2161 @Override
2162 public boolean hasErrors() {
2163 return !errorMessages.isEmpty();
2164 }
2165
2166 /**
2167 * Returns the error message strings reported to this error consumer.
2168 */
2169 public List<String> getErrorMessages() {
2170 return errorMessages;
2171 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002172 }
2173}