blob: dcd36712095e782dddd08d8d810d2b4cf791ac24 [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
jhorvitz6380c2892021-05-03 10:13:52 -070017import static com.google.common.base.MoreObjects.firstNonNull;
jcater64534e22021-05-06 07:56:27 -070018import static com.google.devtools.build.lib.packages.ExecGroup.DEFAULT_EXEC_GROUP_NAME;
juliexxiaff580812020-04-30 15:01:09 -070019
Janak Ramakrishnan7857c792016-03-21 08:35:35 +000020import com.google.common.annotations.VisibleForTesting;
Yun Peng5c34e962016-02-22 15:13:19 +000021import com.google.common.base.Joiner;
Googler59480b92016-07-22 17:06:40 +000022import com.google.common.base.Optional;
tomlua155b532017-11-08 20:12:47 +010023import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010024import com.google.common.base.Predicate;
Yun Pengefd7ca12016-03-03 13:14:38 +000025import com.google.common.base.Predicates;
Florian Weikert082c0542015-08-06 10:24:29 +000026import com.google.common.collect.ImmutableCollection;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import com.google.common.collect.ImmutableList;
28import com.google.common.collect.ImmutableListMultimap;
29import com.google.common.collect.ImmutableMap;
30import com.google.common.collect.ImmutableSet;
Manuel Klimek6d9fb362015-04-30 12:50:55 +000031import com.google.common.collect.ImmutableSortedSet;
John Caterf1e0d342021-03-05 13:44:19 -080032import com.google.common.collect.ImmutableTable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033import com.google.common.collect.Iterables;
34import com.google.common.collect.ListMultimap;
janakrf3e6f252018-01-18 07:45:12 -080035import com.google.common.collect.Lists;
mjhalupkade47f212018-02-12 12:31:21 -080036import com.google.common.collect.Maps;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010037import com.google.common.collect.Multimaps;
38import com.google.common.collect.Sets;
Rumou Duan33bab462016-04-25 17:55:12 +000039import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
plf1f341a62019-04-01 14:02:14 -070040import com.google.devtools.build.lib.actions.ActionKeyContext;
jhorvitz3daedc32020-07-22 18:33:55 -070041import com.google.devtools.build.lib.actions.ActionLookupKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010042import com.google.devtools.build.lib.actions.ActionOwner;
43import com.google.devtools.build.lib.actions.ActionRegistry;
44import com.google.devtools.build.lib.actions.Artifact;
cpeyserac09f0a2018-02-05 09:33:15 -080045import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
tomlu1cdcdf92018-01-16 11:07:51 -080046import com.google.devtools.build.lib.actions.ArtifactRoot;
lberkiee2dcae2018-03-28 05:49:04 -070047import com.google.devtools.build.lib.analysis.AliasProvider.TargetMode;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010048import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
jcater1865d892020-04-14 10:04:29 -070049import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010050import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
gregce79989f92021-02-01 07:01:55 -080051import com.google.devtools.build.lib.analysis.config.ConfigConditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010052import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
jhorvitz7410c802020-07-22 11:55:07 -070053import com.google.devtools.build.lib.analysis.config.CoreOptions;
54import com.google.devtools.build.lib.analysis.config.CoreOptions.IncludeConfigFragmentsEnum;
jcatera666f002020-04-14 14:55:20 -070055import com.google.devtools.build.lib.analysis.config.Fragment;
jhorvitz6380c2892021-05-03 10:13:52 -070056import com.google.devtools.build.lib.analysis.config.FragmentClassSet;
Florian Weikert3f8aac92015-09-07 12:06:02 +000057import com.google.devtools.build.lib.analysis.config.FragmentCollection;
gregcebe55e112018-01-30 11:04:53 -080058import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
gregce7fa23ea2018-01-18 12:46:04 -080059import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
gregce6acfe4e2018-05-25 08:38:39 -070060import com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics;
Philipp Schrader3e969ff2020-12-10 09:05:37 -080061import com.google.devtools.build.lib.analysis.constraints.RuleContextConstraintSemantics;
jcater0a1e9eb2019-12-17 09:58:38 -080062import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
John Cater15c90b32017-12-18 08:34:40 -080063import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
brandjonf1cc4dd2021-02-01 08:53:40 -080064import com.google.devtools.build.lib.analysis.starlark.StarlarkRuleContext;
ulfjack01bf32e2017-11-02 17:50:07 -040065import com.google.devtools.build.lib.analysis.stringtemplate.TemplateContext;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000066import com.google.devtools.build.lib.cmdline.Label;
dslomovfd62e762017-09-19 16:55:53 +020067import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010068import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap;
69import com.google.devtools.build.lib.collect.nestedset.NestedSet;
70import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
brandjonbfd332e2020-12-17 14:56:04 -080071import com.google.devtools.build.lib.events.Event;
Klaus Aehlig16a107d2017-05-31 18:02:43 +020072import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
dslomov44d15712017-12-20 05:42:28 -080073import com.google.devtools.build.lib.packages.Aspect;
Dmitry Lomov15756522016-12-16 16:52:37 +000074import com.google.devtools.build.lib.packages.AspectDescriptor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010075import com.google.devtools.build.lib.packages.Attribute;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076import com.google.devtools.build.lib.packages.AttributeMap;
brandjonbfd332e2020-12-17 14:56:04 -080077import com.google.devtools.build.lib.packages.BazelStarlarkContext;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000078import com.google.devtools.build.lib.packages.BuildType;
cparsons2d67cf92018-05-24 14:02:09 -070079import com.google.devtools.build.lib.packages.BuiltinProvider;
Michael Staibb51251e2015-09-29 23:31:51 +000080import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy;
cparsons78927792017-10-11 00:14:19 +020081import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010082import com.google.devtools.build.lib.packages.FileTarget;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000083import com.google.devtools.build.lib.packages.FilesetEntry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010084import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
dslomovde965ac2017-07-31 21:07:51 +020085import com.google.devtools.build.lib.packages.Info;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010086import com.google.devtools.build.lib.packages.InputFile;
87import com.google.devtools.build.lib.packages.OutputFile;
gregce79989f92021-02-01 07:01:55 -080088import com.google.devtools.build.lib.packages.Package.ConfigSettingVisibilityPolicy;
cushon34ff85e2017-11-15 08:59:27 -080089import com.google.devtools.build.lib.packages.PackageSpecification.PackageGroupContents;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090import com.google.devtools.build.lib.packages.RawAttributeMapper;
dslomovc13bb392017-08-02 23:29:54 +020091import com.google.devtools.build.lib.packages.RequiredProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010092import com.google.devtools.build.lib.packages.Rule;
93import com.google.devtools.build.lib.packages.RuleClass;
brandjonf1cc4dd2021-02-01 08:53:40 -080094import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
Googler995ef632019-09-04 12:25:41 -070095import com.google.devtools.build.lib.packages.SymbolGenerator;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010096import com.google.devtools.build.lib.packages.Target;
97import com.google.devtools.build.lib.packages.TargetUtils;
Googlerc5fcc862019-09-06 16:17:47 -070098import com.google.devtools.build.lib.packages.Type;
99import com.google.devtools.build.lib.packages.Type.LabelClass;
adonovan028e1ad2020-09-07 07:09:59 -0700100import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
mschaller859c9ac2020-09-25 16:09:19 -0700101import com.google.devtools.build.lib.server.FailureDetails.Analysis;
102import com.google.devtools.build.lib.server.FailureDetails.Analysis.Code;
103import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
janakr9c101402018-03-10 06:48:59 -0800104import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
juliexxia6fe70c22020-05-18 14:38:42 -0700105import com.google.devtools.build.lib.skyframe.SaneAnalysisException;
mschaller859c9ac2020-09-25 16:09:19 -0700106import com.google.devtools.build.lib.util.DetailedExitCode;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100107import com.google.devtools.build.lib.util.FileTypeSet;
cparsons0623d3c2018-10-23 16:06:30 -0700108import com.google.devtools.build.lib.util.OS;
Greg Estrend5353252016-08-11 22:13:31 +0000109import com.google.devtools.build.lib.util.OrderedSetMultimap;
Googlere49cd592016-07-29 19:32:38 +0000110import com.google.devtools.build.lib.util.StringUtil;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100111import com.google.devtools.build.lib.vfs.FileSystemUtils;
112import com.google.devtools.build.lib.vfs.PathFragment;
gregce31e44792020-04-27 09:10:40 -0700113import java.util.ArrayList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100114import java.util.Collection;
115import java.util.HashMap;
116import java.util.HashSet;
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +0000117import java.util.LinkedHashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100118import java.util.List;
119import java.util.Map;
120import java.util.Set;
dslomov44d15712017-12-20 05:42:28 -0800121import java.util.stream.Collectors;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100122import javax.annotation.Nullable;
adonovan450c7ad2020-09-14 13:00:21 -0700123import net.starlark.java.eval.EvalException;
brandjonbfd332e2020-12-17 14:56:04 -0800124import net.starlark.java.eval.Mutability;
brandjon4f331eb2021-02-01 09:09:39 -0800125import net.starlark.java.eval.Starlark;
adonovan450c7ad2020-09-14 13:00:21 -0700126import net.starlark.java.eval.StarlarkSemantics;
brandjonbfd332e2020-12-17 14:56:04 -0800127import net.starlark.java.eval.StarlarkThread;
adonovan450c7ad2020-09-14 13:00:21 -0700128import net.starlark.java.syntax.Location;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100129
130/**
Lukacs Berki2300cd62016-05-19 11:06:37 +0000131 * The totality of data available during the analysis of a rule.
Janak Ramakrishnan81c5bd82016-03-22 20:07:43 +0000132 *
jcater02ce2a62020-04-07 08:06:00 -0700133 * <p>These objects should not outlast the analysis phase. Do not pass them to {@link
134 * com.google.devtools.build.lib.actions.Action} objects or other persistent objects. There are
135 * internal tests to ensure that RuleContext objects are not persisted that check the name of this
136 * class, so update those tests if you change this class's name.
Lukacs Berki2300cd62016-05-19 11:06:37 +0000137 *
ulfjack26d0e492017-08-07 13:42:33 +0200138 * @see com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100139 */
140public final class RuleContext extends TargetContext
brandjonbfd332e2020-12-17 14:56:04 -0800141 implements ActionConstructionContext, ActionRegistry, RuleErrorConsumer, AutoCloseable {
Carmi Grushko33aa3062016-11-11 02:45:29 +0000142
brandjon2e34f1a2020-12-17 16:42:00 -0800143 public boolean isAllowTagsPropagation() {
144 return starlarkSemantics.getBool(BuildLanguageOptions.EXPERIMENTAL_ALLOW_TAGS_PROPAGATION);
ishikhman94c24b32019-08-30 04:46:25 -0700145 }
146
jcater0de10972020-04-07 12:15:05 -0700147 /** Custom dependency validation logic. */
148 public interface PrerequisiteValidator {
149 /**
150 * Checks whether the rule in {@code contextBuilder} is allowed to depend on {@code
151 * prerequisite} through the attribute {@code attribute}.
152 *
153 * <p>Can be used for enforcing any organization-specific policies about the layout of the
154 * workspace.
155 */
156 void validate(
157 Builder contextBuilder, ConfiguredTargetAndData prerequisite, Attribute attribute);
158 }
159
160 /** The configured version of FilesetEntry. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100161 @Immutable
162 public static final class ConfiguredFilesetEntry {
163 private final FilesetEntry entry;
164 private final TransitiveInfoCollection src;
165 private final ImmutableList<TransitiveInfoCollection> files;
166
167 ConfiguredFilesetEntry(FilesetEntry entry, TransitiveInfoCollection src) {
168 this.entry = entry;
169 this.src = src;
170 this.files = null;
171 }
172
173 ConfiguredFilesetEntry(FilesetEntry entry, ImmutableList<TransitiveInfoCollection> files) {
174 this.entry = entry;
175 this.src = null;
176 this.files = files;
177 }
178
179 public FilesetEntry getEntry() {
180 return entry;
181 }
182
183 public TransitiveInfoCollection getSrc() {
184 return src;
185 }
186
187 /**
188 * Targets from FilesetEntry.files, or null if the user omitted it.
189 */
190 @Nullable
Ulf Adams10993fe2016-04-19 12:55:12 +0000191 public ImmutableList<TransitiveInfoCollection> getFiles() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100192 return files;
193 }
194 }
195
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000196 private static final String HOST_CONFIGURATION_PROGRESS_TAG = "for host";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100197
198 private final Rule rule;
dslomov44d15712017-12-20 05:42:28 -0800199 /**
brandjonf1cc4dd2021-02-01 08:53:40 -0800200 * A list of all aspects applied to the target. If this {@code RuleContext} is for a rule
201 * implementation, {@code aspects} is an empty list.
dslomov44d15712017-12-20 05:42:28 -0800202 *
brandjonf1cc4dd2021-02-01 08:53:40 -0800203 * <p>Otherwise, the last aspect in the list is the one that this {@code RuleContext} is for.
dslomov44d15712017-12-20 05:42:28 -0800204 */
205 private final ImmutableList<Aspect> aspects;
brandjonf1cc4dd2021-02-01 08:53:40 -0800206
Dmitry Lomov15756522016-12-16 16:52:37 +0000207 private final ImmutableList<AspectDescriptor> aspectDescriptors;
janakr9c101402018-03-10 06:48:59 -0800208 private final ListMultimap<String, ConfiguredTargetAndData> targetMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100209 private final ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap;
Lukacs Berki7894c182016-05-10 12:07:01 +0000210 private final ImmutableMap<Label, ConfigMatchingProvider> configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000211 private final AspectAwareAttributeMapper attributes;
Googler993f1de2018-02-20 02:31:10 -0800212 private final ImmutableSet<String> enabledFeatures;
213 private final ImmutableSet<String> disabledFeatures;
Michael Staib8824d5e2016-01-20 21:37:05 +0000214 private final String ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000215 private final BuildConfiguration hostConfiguration;
Michael Staibb51251e2015-09-29 23:31:51 +0000216 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
jhorvitz6380c2892021-05-03 10:13:52 -0700217 private final FragmentClassSet universalFragments;
cparsonse8d450c2018-10-04 16:01:53 -0700218 private final RuleErrorConsumer reporter;
juliexxiab5f9d742020-04-09 13:07:13 -0700219 @Nullable private final ToolchainCollection<ResolvedToolchainContext> toolchainContexts;
jcater802551e2020-04-15 09:59:58 -0700220 private final ConstraintSemantics<RuleContext> constraintSemantics;
gregce966dc232019-10-18 15:34:07 -0700221 private final ImmutableSet<String> requiredConfigFragments;
gregce31e44792020-04-27 09:10:40 -0700222 private final List<Expander> makeVariableExpanders = new ArrayList<>();
John Caterf1e0d342021-03-05 13:44:19 -0800223 private final ImmutableTable<String, String, String> execProperties;
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000224
juliexxiaff580812020-04-30 15:01:09 -0700225 /** Map of exec group names to ActionOwners. */
226 private final Map<String, ActionOwner> actionOwners = new HashMap<>();
227
jhorvitz3daedc32020-07-22 18:33:55 -0700228 private final SymbolGenerator<ActionLookupKey> actionOwnerSymbolGenerator;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100229
230 /* lazily computed cache for Make variables, computed from the above. See get... method */
231 private transient ConfigurationMakeVariableContext configurationMakeVariableContext = null;
232
brandjonbfd332e2020-12-17 14:56:04 -0800233 /**
brandjon2e34f1a2020-12-17 16:42:00 -0800234 * The StarlarkSemantics to use for rule analysis. Should be the same as what's reported by the
235 * AnalysisEnvironment, but saving it here is more convenient since {@link
236 * AnalysisEnvironment#getStarlarkSemantics()} can throw InterruptedException.
237 */
238 private final StarlarkSemantics starlarkSemantics;
239
240 /**
brandjonbfd332e2020-12-17 14:56:04 -0800241 * Thread used for any Starlark evaluation during analysis, e.g. rule implementation function for
242 * a Starlark-defined rule, or Starlarkified helper logic for native rules that have been
243 * partially migrated to {@code @_builtins}.
244 */
245 private final StarlarkThread starlarkThread;
brandjonf1cc4dd2021-02-01 08:53:40 -0800246 /**
247 * The {@code ctx} object passed to a Starlark-defined rule's or aspect's implementation function.
248 * This object may outlive the analysis phase, e.g. if it is returned in a provider.
249 *
250 * <p>Initialized explicitly by calling {@link #initStarlarkRuleContext}. Native rules that do not
251 * pass this object to {@code @_builtins} might avoid the cost of initializing this object, but
252 * for everyone else it's mandatory.
253 */
254 @Nullable private StarlarkRuleContext starlarkRuleContext;
brandjonbfd332e2020-12-17 14:56:04 -0800255
Dmitry Lomovace678e2015-12-16 15:10:20 +0000256 private RuleContext(
257 Builder builder,
Nathan Harmatafcb17112016-04-13 16:56:58 +0000258 AttributeMap attributes,
janakr9c101402018-03-10 06:48:59 -0800259 ListMultimap<String, ConfiguredTargetAndData> targetMap,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100260 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap,
Lukacs Berki7894c182016-05-10 12:07:01 +0000261 ImmutableMap<Label, ConfigMatchingProvider> configConditions,
jhorvitz6380c2892021-05-03 10:13:52 -0700262 FragmentClassSet universalFragments,
Michael Staib8824d5e2016-01-20 21:37:05 +0000263 String ruleClassNameForLogging,
jhorvitz3daedc32020-07-22 18:33:55 -0700264 ActionLookupKey actionLookupKey,
John Cater13263f72017-05-24 19:06:47 +0200265 ImmutableMap<String, Attribute> aspectAttributes,
juliexxiab5f9d742020-04-09 13:07:13 -0700266 @Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts,
jcater802551e2020-04-15 09:59:58 -0700267 ConstraintSemantics<RuleContext> constraintSemantics,
brandjonbfd332e2020-12-17 14:56:04 -0800268 ImmutableSet<String> requiredConfigFragments,
269 String toolsRepository,
270 StarlarkSemantics starlarkSemantics,
271 Mutability mutability)
juliexxia6fe70c22020-05-18 14:38:42 -0700272 throws InvalidExecGroupException {
lpino5fe7ed02018-07-18 05:55:23 -0700273 super(
274 builder.env,
275 builder.target.getAssociatedRule(),
276 builder.configuration,
277 builder.prerequisiteMap.get(null),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100278 builder.visibility);
lpino5fe7ed02018-07-18 05:55:23 -0700279 this.rule = builder.target.getAssociatedRule();
dslomov44d15712017-12-20 05:42:28 -0800280 this.aspects = builder.aspects;
281 this.aspectDescriptors =
282 builder
283 .aspects
284 .stream()
285 .map(a -> a.getDescriptor())
286 .collect(ImmutableList.toImmutableList());
Michael Staibb51251e2015-09-29 23:31:51 +0000287 this.configurationFragmentPolicy = builder.configurationFragmentPolicy;
lberki78651d42018-04-06 01:52:58 -0700288 this.universalFragments = universalFragments;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100289 this.targetMap = targetMap;
290 this.filesetEntryMap = filesetEntryMap;
291 this.configConditions = configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000292 this.attributes = new AspectAwareAttributeMapper(attributes, aspectAttributes);
Googler993f1de2018-02-20 02:31:10 -0800293 Set<String> allEnabledFeatures = new HashSet<>();
294 Set<String> allDisabledFeatures = new HashSet<>();
295 getAllFeatures(allEnabledFeatures, allDisabledFeatures);
296 this.enabledFeatures = ImmutableSortedSet.copyOf(allEnabledFeatures);
297 this.disabledFeatures = ImmutableSortedSet.copyOf(allDisabledFeatures);
Michael Staib8824d5e2016-01-20 21:37:05 +0000298 this.ruleClassNameForLogging = ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000299 this.hostConfiguration = builder.hostConfiguration;
janakreaff19c2019-01-31 13:59:40 -0800300 this.actionOwnerSymbolGenerator = new SymbolGenerator<>(actionLookupKey);
Florian Weikertb8a6a942015-09-25 12:36:08 +0000301 reporter = builder.reporter;
juliexxiab5f9d742020-04-09 13:07:13 -0700302 this.toolchainContexts = toolchainContexts;
juliexxia3eb806e2020-07-15 08:42:34 -0700303 this.execProperties = parseExecProperties(builder.rawExecProperties);
gregce6acfe4e2018-05-25 08:38:39 -0700304 this.constraintSemantics = constraintSemantics;
gregce966dc232019-10-18 15:34:07 -0700305 this.requiredConfigFragments = requiredConfigFragments;
brandjon2e34f1a2020-12-17 16:42:00 -0800306 this.starlarkSemantics = starlarkSemantics;
307 this.starlarkThread = createStarlarkThread(toolsRepository, mutability); // uses above state
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100308 }
309
Googler993f1de2018-02-20 02:31:10 -0800310 private void getAllFeatures(Set<String> allEnabledFeatures, Set<String> allDisabledFeatures) {
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000311 Set<String> globallyEnabled = new HashSet<>();
312 Set<String> globallyDisabled = new HashSet<>();
313 parseFeatures(getConfiguration().getDefaultFeatures(), globallyEnabled, globallyDisabled);
314 Set<String> packageEnabled = new HashSet<>();
315 Set<String> packageDisabled = new HashSet<>();
316 parseFeatures(getRule().getPackage().getFeatures(), packageEnabled, packageDisabled);
Googler8e3afcc2017-12-20 08:10:21 -0800317 Set<String> ruleEnabled = new HashSet<>();
318 Set<String> ruleDisabled = new HashSet<>();
319 if (attributes().has("features", Type.STRING_LIST)) {
320 parseFeatures(attributes().get("features", Type.STRING_LIST), ruleEnabled, ruleDisabled);
321 }
Googler993f1de2018-02-20 02:31:10 -0800322
Googler8e3afcc2017-12-20 08:10:21 -0800323 Set<String> ruleDisabledFeatures =
324 Sets.union(ruleDisabled, Sets.difference(packageDisabled, ruleEnabled));
Googler993f1de2018-02-20 02:31:10 -0800325 allDisabledFeatures.addAll(Sets.union(ruleDisabledFeatures, globallyDisabled));
Googler993f1de2018-02-20 02:31:10 -0800326
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000327 Set<String> packageFeatures =
328 Sets.difference(Sets.union(globallyEnabled, packageEnabled), packageDisabled);
Googler8e3afcc2017-12-20 08:10:21 -0800329 Set<String> ruleFeatures =
330 Sets.difference(Sets.union(packageFeatures, ruleEnabled), ruleDisabled);
Googler993f1de2018-02-20 02:31:10 -0800331 allEnabledFeatures.addAll(Sets.difference(ruleFeatures, globallyDisabled));
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000332 }
333
334 private void parseFeatures(Iterable<String> features, Set<String> enabled, Set<String> disabled) {
335 for (String feature : features) {
336 if (feature.startsWith("-")) {
337 disabled.add(feature.substring(1));
338 } else if (feature.equals("no_layering_check")) {
339 // TODO(bazel-team): Remove once we do not have BUILD files left that contain
340 // 'no_layering_check'.
341 disabled.add(feature.substring(3));
342 } else {
343 enabled.add(feature);
344 }
345 }
346 }
347
dslomovfd62e762017-09-19 16:55:53 +0200348 public RepositoryName getRepository() {
349 return rule.getRepository();
350 }
351
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100352 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800353 public ArtifactRoot getBinDirectory() {
Googler0617f2c2020-10-22 08:43:54 -0700354 return getConfiguration().getBinDirectory(getLabel().getRepository());
dslomovfd62e762017-09-19 16:55:53 +0200355 }
356
Googler36fa3852020-10-13 13:30:14 -0700357 public ArtifactRoot getIncludeDirectory() {
Googler0617f2c2020-10-22 08:43:54 -0700358 return getConfiguration().getIncludeDirectory(getLabel().getRepository());
Googler36fa3852020-10-13 13:30:14 -0700359 }
360
Googler4e7b1e52020-10-09 11:58:45 -0700361 public ArtifactRoot getGenfilesDirectory() {
Googler0617f2c2020-10-22 08:43:54 -0700362 return getConfiguration().getGenfilesDirectory(getLabel().getRepository());
Googler4e7b1e52020-10-09 11:58:45 -0700363 }
364
Googler36fa3852020-10-13 13:30:14 -0700365 public ArtifactRoot getCoverageMetadataDirectory() {
Googler0617f2c2020-10-22 08:43:54 -0700366 return getConfiguration().getCoverageMetadataDirectory(getLabel().getRepository());
Googler36fa3852020-10-13 13:30:14 -0700367 }
368
369 public ArtifactRoot getTestLogsDirectory() {
Googler0617f2c2020-10-22 08:43:54 -0700370 return getConfiguration().getTestLogsDirectory(getLabel().getRepository());
Googler36fa3852020-10-13 13:30:14 -0700371 }
372
Googler4e7b1e52020-10-09 11:58:45 -0700373 public PathFragment getBinFragment() {
Googler0617f2c2020-10-22 08:43:54 -0700374 return getConfiguration().getBinFragment(getLabel().getRepository());
Googler4e7b1e52020-10-09 11:58:45 -0700375 }
376
377 public PathFragment getGenfilesFragment() {
Googler0617f2c2020-10-22 08:43:54 -0700378 return getConfiguration().getGenfilesFragment(getLabel().getRepository());
Googler4e7b1e52020-10-09 11:58:45 -0700379 }
380
dslomovfd62e762017-09-19 16:55:53 +0200381 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800382 public ArtifactRoot getMiddlemanDirectory() {
Googler0617f2c2020-10-22 08:43:54 -0700383 return getConfiguration().getMiddlemanDirectory(getLabel().getRepository());
dslomovfd62e762017-09-19 16:55:53 +0200384 }
cparsons88821922017-10-11 01:21:46 +0200385
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100386 public Rule getRule() {
387 return rule;
388 }
389
dslomov44d15712017-12-20 05:42:28 -0800390 public ImmutableList<Aspect> getAspects() {
391 return aspects;
392 }
393
394 /**
cparsonse8d450c2018-10-04 16:01:53 -0700395 * If this target's configuration suppresses analysis failures, this returns a list
396 * of strings, where each string corresponds to a description of an error that occurred during
397 * processing this target.
398 *
399 * @throws IllegalStateException if this target's configuration does not suppress analysis
400 * failures (if {@code getConfiguration().allowAnalysisFailures()} is false)
401 */
402 public List<String> getSuppressedErrorMessages() {
403 Preconditions.checkState(getConfiguration().allowAnalysisFailures(),
404 "Error messages can only be retrieved via RuleContext if allow_analysis_failures is true");
405 Preconditions.checkState(reporter instanceof SuppressingErrorReporter,
406 "Unexpected error reporter");
407 return ((SuppressingErrorReporter) reporter).getErrorMessages();
408 }
409
410 /**
dslomov44d15712017-12-20 05:42:28 -0800411 * If this <code>RuleContext</code> is for an aspect implementation, returns that aspect.
412 * (it is the last aspect in the list of aspects applied to a target; all other aspects
413 * are the ones main aspect sees as specified by its "required_aspect_providers")
414 * Otherwise returns <code>null</code>.
415 */
416 @Nullable
417 public Aspect getMainAspect() {
brandjonf1cc4dd2021-02-01 08:53:40 -0800418 return aspects.isEmpty() ? null : Iterables.getLast(aspects);
dslomov44d15712017-12-20 05:42:28 -0800419 }
420
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100421 /**
Michael Staib8824d5e2016-01-20 21:37:05 +0000422 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
423 */
424 public String getRuleClassNameForLogging() {
425 return ruleClassNameForLogging;
426 }
427
428 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +0000429 * Returns the workspace name for the rule.
430 */
431 public String getWorkspaceName() {
Googlerf7d370a2021-01-19 08:17:23 -0800432 return rule.getPackage().getWorkspaceName();
Kristina Chodorow91876f02015-02-27 17:14:12 +0000433 }
434
435 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100436 * The configuration conditions that trigger this rule's configurable attributes.
437 */
gregce593f7f92017-09-19 02:02:21 +0200438 public ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100439 return configConditions;
440 }
441
442 /**
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000443 * Returns the host configuration for this rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100444 */
445 public BuildConfiguration getHostConfiguration() {
Greg Estren9eb1cf02015-06-26 22:18:35 +0000446 return hostConfiguration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100447 }
448
449 /**
Dmitry Lomov503c2f72017-02-23 08:55:47 +0000450 * All aspects applied to the rule.
451 */
452 public ImmutableList<AspectDescriptor> getAspectDescriptors() {
453 return aspectDescriptors;
454 }
455
456 /**
Greg Estren7f534232016-12-01 21:38:25 +0000457 * Accessor for the attributes of the rule and its aspects.
458 *
459 * <p>The rule's native attributes can be queried both on their structure / existence and values
460 * Aspect attributes can only be queried on their structure.
461 *
462 * <p>This should be the sole interface for reading rule/aspect attributes in {@link RuleContext}.
463 * Don't expose other access points through new public methods.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100464 */
465 public AttributeMap attributes() {
466 return attributes;
467 }
468
cparsons0dcffc52017-10-13 23:40:31 +0200469 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100470 public boolean hasErrors() {
cparsons146b9ff2019-06-21 09:45:14 -0700471 return reporter.hasErrors();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100472 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000473
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100474 /**
475 * Returns an immutable map from attribute name to list of configured targets for that attribute.
476 */
477 public ListMultimap<String, ? extends TransitiveInfoCollection> getConfiguredTargetMap() {
janakr9c101402018-03-10 06:48:59 -0800478 return Multimaps.transformValues(targetMap, ConfiguredTargetAndData::getConfiguredTarget);
janakrf3e6f252018-01-18 07:45:12 -0800479 }
480
janakr65866212018-03-10 22:30:33 -0800481 /**
482 * Returns an immutable map from attribute name to list of {@link ConfiguredTargetAndData} objects
483 * for that attribute.
484 */
485 public ListMultimap<String, ConfiguredTargetAndData> getConfiguredTargetAndDataMap() {
486 return targetMap;
487 }
488
jcater0b8280e2020-08-25 08:23:03 -0700489 /** Returns the {@link ConfiguredTargetAndData} the given attribute. */
490 public List<ConfiguredTargetAndData> getPrerequisiteConfiguredTargets(String attributeName) {
491 return targetMap.get(attributeName);
mjhalupkade47f212018-02-12 12:31:21 -0800492 }
493
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100494 /**
495 * Returns an immutable map from attribute name to list of fileset entries.
496 */
497 public ListMultimap<String, ConfiguredFilesetEntry> getFilesetEntryMap() {
498 return filesetEntryMap;
499 }
500
501 @Override
502 public ActionOwner getActionOwner() {
juliexxiaff580812020-04-30 15:01:09 -0700503 return getActionOwner(DEFAULT_EXEC_GROUP_NAME);
504 }
505
506 @Override
juliexxia2c97d382020-06-12 10:16:26 -0700507 @Nullable
juliexxiaff580812020-04-30 15:01:09 -0700508 public ActionOwner getActionOwner(String execGroup) {
509 if (actionOwners.containsKey(execGroup)) {
510 return actionOwners.get(execGroup);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100511 }
juliexxia2c97d382020-06-12 10:16:26 -0700512 if (toolchainContexts != null && !toolchainContexts.hasToolchainContext(execGroup)) {
513 return null;
514 }
juliexxiaff580812020-04-30 15:01:09 -0700515 ActionOwner actionOwner =
516 createActionOwner(
517 rule,
518 aspectDescriptors,
519 getConfiguration(),
juliexxia6fe70c22020-05-18 14:38:42 -0700520 getExecProperties(execGroup, execProperties),
Yuvald0676692021-03-05 09:53:44 -0800521 getExecutionPlatform(execGroup),
522 ImmutableSet.of(execGroup));
juliexxiaff580812020-04-30 15:01:09 -0700523 actionOwners.put(execGroup, actionOwner);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100524 return actionOwner;
525 }
526
527 /**
plf1f341a62019-04-01 14:02:14 -0700528 * We have to re-implement this method here because it is declared in the interface {@link
529 * ActionConstructionContext}. This class inherits from {@link TargetContext} which doesn't
530 * implement the {@link ActionConstructionContext} interface.
531 */
532 @Override
533 public ActionKeyContext getActionKeyContext() {
534 return super.getActionKeyContext();
535 }
536
537 /**
janakreaff19c2019-01-31 13:59:40 -0800538 * An opaque symbol generator to be used when identifying objects by their action owner/index of
539 * creation. Only needed if an object needs to know whether it was created by the same action
540 * owner in the same order as another object. Each symbol must call {@link
541 * SymbolGenerator#generate} separately to obtain a unique object.
542 */
543 public SymbolGenerator<?> getSymbolGenerator() {
544 return actionOwnerSymbolGenerator;
545 }
546
547 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100548 * Returns a configuration fragment for this this target.
549 */
550 @Nullable
gregcebe55e112018-01-30 11:04:53 -0800551 public <T extends Fragment> T getFragment(Class<T> fragment, ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800552 return getFragment(fragment, fragment.getSimpleName(), "", transition);
Florian Weikertd2a24612015-09-07 14:35:23 +0000553 }
554
555 @Nullable
David Ostrovskya1388772020-07-08 12:11:01 -0700556 <T extends Fragment> T getFragment(
557 Class<T> fragment,
558 String name,
559 String additionalErrorMessage,
560 ConfigurationTransition transition) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100561 // TODO(bazel-team): The fragments can also be accessed directly through BuildConfiguration.
562 // Can we lock that down somehow?
gregcec7b21212017-12-21 12:40:20 -0800563 Preconditions.checkArgument(isLegalFragment(fragment, transition),
Florian Weikertd2a24612015-09-07 14:35:23 +0000564 "%s has to declare '%s' as a required fragment "
565 + "in %s configuration in order to access it.%s",
gregcec7b21212017-12-21 12:40:20 -0800566 getRuleClassNameForLogging(), name, FragmentCollection.getConfigurationName(transition),
Florian Weikertd2a24612015-09-07 14:35:23 +0000567 additionalErrorMessage);
gregcec7b21212017-12-21 12:40:20 -0800568 return getConfiguration(transition).getFragment(fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100569 }
570
Florian Weikert082c0542015-08-06 10:24:29 +0000571 @Nullable
Florian Weikert3f8aac92015-09-07 12:06:02 +0000572 public <T extends Fragment> T getFragment(Class<T> fragment) {
gregce7fa23ea2018-01-18 12:46:04 -0800573 // No transition means target configuration.
574 return getFragment(fragment, NoTransition.INSTANCE);
Florian Weikert082c0542015-08-06 10:24:29 +0000575 }
576
Florian Weikert3f8aac92015-09-07 12:06:02 +0000577 @Nullable
gregceb100b1d2020-05-20 10:22:17 -0700578 public Fragment getStarlarkFragment(String name, ConfigurationTransition transition)
adonovanb8eae2d2019-12-09 15:11:06 -0800579 throws EvalException {
Florian Weikert1c2eeac2015-10-28 10:00:53 +0000580 Class<? extends Fragment> fragmentClass =
gregceb100b1d2020-05-20 10:22:17 -0700581 getConfiguration(transition).getStarlarkFragmentByName(name);
Florian Weikertd2a24612015-09-07 14:35:23 +0000582 if (fragmentClass == null) {
583 return null;
584 }
adonovanb8eae2d2019-12-09 15:11:06 -0800585 try {
586 return getFragment(
587 fragmentClass,
588 name,
589 String.format(
590 " Please update the '%1$sfragments' argument of the rule definition "
591 + "(for example: %1$sfragments = [\"%2$s\"])",
592 transition.isHostTransition() ? "host_" : "", name),
593 transition);
594 } catch (IllegalArgumentException ex) { // fishy
adonovana6287362020-08-07 07:15:30 -0700595 throw new EvalException(ex.getMessage());
adonovanb8eae2d2019-12-09 15:11:06 -0800596 }
Florian Weikert3f8aac92015-09-07 12:06:02 +0000597 }
598
gregceb100b1d2020-05-20 10:22:17 -0700599 public ImmutableCollection<String> getStarlarkFragmentNames(ConfigurationTransition transition) {
600 return getConfiguration(transition).getStarlarkFragmentNames();
Florian Weikert3f8aac92015-09-07 12:06:02 +0000601 }
602
603 public <T extends Fragment> boolean isLegalFragment(
gregcebe55e112018-01-30 11:04:53 -0800604 Class<T> fragment, ConfigurationTransition transition) {
lberki78651d42018-04-06 01:52:58 -0700605 return universalFragments.contains(fragment)
gregcec7b21212017-12-21 12:40:20 -0800606 || configurationFragmentPolicy.isLegalConfigurationFragment(fragment, transition);
Florian Weikert082c0542015-08-06 10:24:29 +0000607 }
608
Ulf Adamsea11fc52015-08-04 14:23:58 +0000609 public <T extends Fragment> boolean isLegalFragment(Class<T> fragment) {
gregce7fa23ea2018-01-18 12:46:04 -0800610 // No transition means target configuration.
611 return isLegalFragment(fragment, NoTransition.INSTANCE);
Florian Weikert3f8aac92015-09-07 12:06:02 +0000612 }
Florian Weikertd2a24612015-09-07 14:35:23 +0000613
gregcee861ffc2018-02-02 17:06:49 -0800614 private BuildConfiguration getConfiguration(ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800615 return transition.isHostTransition() ? hostConfiguration : getConfiguration();
Ulf Adamsea11fc52015-08-04 14:23:58 +0000616 }
617
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100618 @Override
jhorvitz3daedc32020-07-22 18:33:55 -0700619 public ActionLookupKey getOwner() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100620 return getAnalysisEnvironment().getOwner();
621 }
622
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000623 public ImmutableList<Artifact> getBuildInfo(BuildInfoKey key) throws InterruptedException {
plf1f341a62019-04-01 14:02:14 -0700624 return getAnalysisEnvironment()
625 .getBuildInfo(
626 AnalysisUtils.isStampingEnabled(this, getConfiguration()), key, getConfiguration());
Ulf Adamsc272e0f2015-04-22 19:56:21 +0000627 }
628
Yuvald0676692021-03-05 09:53:44 -0800629 /**
630 * Computes a map of exec properties given the execution platform, taking only properties in exec
631 * groups that are applicable to this action. Properties for specific exec groups take precedence
632 * over properties that don't specify an exec group.
633 */
Googlerb5082462019-08-26 14:28:09 -0700634 private static ImmutableMap<String, String> computeExecProperties(
Yuvald0676692021-03-05 09:53:44 -0800635 Map<String, String> targetExecProperties,
636 @Nullable PlatformInfo executionPlatform,
637 Set<String> execGroups) {
Googlerb5082462019-08-26 14:28:09 -0700638 Map<String, String> execProperties = new HashMap<>();
639
640 if (executionPlatform != null) {
John Caterf1e0d342021-03-05 13:44:19 -0800641 ImmutableTable<String, String, String> execPropertiesPerGroup =
Yuvald0676692021-03-05 09:53:44 -0800642 parseExecGroups(executionPlatform.execProperties());
643
John Caterf1e0d342021-03-05 13:44:19 -0800644 if (execPropertiesPerGroup.containsRow(DEFAULT_EXEC_GROUP_NAME)) {
645 execProperties.putAll(execPropertiesPerGroup.row(DEFAULT_EXEC_GROUP_NAME));
Yuvald0676692021-03-05 09:53:44 -0800646 }
647
John Caterf1e0d342021-03-05 13:44:19 -0800648 for (String execGroup : execPropertiesPerGroup.rowKeySet()) {
649 if (execGroups.contains(execGroup)) {
650 execProperties.putAll(execPropertiesPerGroup.row(execGroup));
Yuvald0676692021-03-05 09:53:44 -0800651 }
652 }
Googlerb5082462019-08-26 14:28:09 -0700653 }
654
655 // If the same key occurs both in the platform and in target-specific properties, the
656 // value is taken from target-specific properties (effectively overriding the platform
657 // properties).
658 execProperties.putAll(targetExecProperties);
659 return ImmutableMap.copyOf(execProperties);
660 }
661
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000662 @VisibleForTesting
Carmi Grushko33aa3062016-11-11 02:45:29 +0000663 public static ActionOwner createActionOwner(
664 Rule rule,
Dmitry Lomov15756522016-12-16 16:52:37 +0000665 ImmutableList<AspectDescriptor> aspectDescriptors,
John Caterec5d2ed2018-01-04 11:52:21 -0800666 BuildConfiguration configuration,
Googlerb5082462019-08-26 14:28:09 -0700667 Map<String, String> targetExecProperties,
Yuvald0676692021-03-05 09:53:44 -0800668 @Nullable PlatformInfo executionPlatform,
669 Set<String> execGroups) {
Carmi Grushko4665e702016-11-09 21:51:27 +0000670 return ActionOwner.create(
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000671 rule.getLabel(),
Dmitry Lomov15756522016-12-16 16:52:37 +0000672 aspectDescriptors,
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000673 rule.getLocation(),
674 configuration.getMnemonic(),
675 rule.getTargetKind(),
676 configuration.checksum(),
shahan50f99d52018-03-10 05:14:09 -0800677 configuration.toBuildEvent(),
John Caterec5d2ed2018-01-04 11:52:21 -0800678 configuration.isHostConfiguration() ? HOST_CONFIGURATION_PROGRESS_TAG : null,
Yuvald0676692021-03-05 09:53:44 -0800679 computeExecProperties(targetExecProperties, executionPlatform, execGroups),
John Caterec5d2ed2018-01-04 11:52:21 -0800680 executionPlatform);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100681 }
682
683 @Override
janakrd4591972021-04-14 08:37:06 -0700684 public void registerAction(ActionAnalysisMetadata action) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100685 getAnalysisEnvironment().registerAction(action);
686 }
687
688 /**
689 * Convenience function for subclasses to report non-attribute-specific
690 * errors in the current rule.
691 */
692 @Override
693 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000694 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100695 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000696
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100697 /**
698 * Convenience function for subclasses to report non-attribute-specific
699 * warnings in the current rule.
700 */
701 @Override
702 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000703 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100704 }
705
706 /**
707 * Convenience function for subclasses to report attribute-specific errors in
708 * the current rule.
709 *
710 * <p>If the name of the attribute starts with <code>$</code>
711 * it is replaced with a string <code>(an implicit dependency)</code>.
712 */
713 @Override
714 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000715 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100716 }
717
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000718 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100719 * Like attributeError, but does not mark the configured target as errored.
720 *
721 * <p>If the name of the attribute starts with <code>$</code>
722 * it is replaced with a string <code>(an implicit dependency)</code>.
723 */
724 @Override
725 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000726 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100727 }
728
729 /**
730 * Returns an artifact beneath the root of either the "bin" or "genfiles"
731 * tree, whose path is based on the name of this target and the current
732 * configuration. The choice of which tree to use is based on the rule with
733 * which this target (which must be an OutputFile or a Rule) is associated.
734 */
735 public Artifact createOutputArtifact() {
cparsons0623d3c2018-10-23 16:06:30 -0700736 Target target = getTarget();
737 PathFragment rootRelativePath = getPackageDirectory()
738 .getRelative(PathFragment.create(target.getName()));
739
740 return internalCreateOutputArtifact(rootRelativePath, target, OutputFile.Kind.FILE);
741 }
742
743 /**
744 * Returns an artifact beneath the root of either the "bin" or "genfiles"
745 * tree, whose path is based on the name of this target and the current
746 * configuration, with a script suffix appropriate for the current host platform. ({@code .cmd}
747 * for Windows, otherwise {@code .sh}). The choice of which tree to use is based on the rule with
748 * which this target (which must be an OutputFile or a Rule) is associated.
749 */
750 public Artifact createOutputArtifactScript() {
751 Target target = getTarget();
752 // TODO(laszlocsomor): Use the execution platform, not the host platform.
753 boolean isExecutedOnWindows = OS.getCurrent() == OS.WINDOWS;
754
755 String fileExtension = isExecutedOnWindows ? ".cmd" : ".sh";
756
757 PathFragment rootRelativePath = getPackageDirectory()
758 .getRelative(PathFragment.create(target.getName() + fileExtension));
759
760 return internalCreateOutputArtifact(rootRelativePath, target, OutputFile.Kind.FILE);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100761 }
762
763 /**
764 * Returns the output artifact of an {@link OutputFile} of this target.
765 *
766 * @see #createOutputArtifact()
767 */
768 public Artifact createOutputArtifact(OutputFile out) {
cparsons0623d3c2018-10-23 16:06:30 -0700769 PathFragment packageRelativePath = getPackageDirectory()
770 .getRelative(PathFragment.create(out.getName()));
771 return internalCreateOutputArtifact(packageRelativePath, out, out.getKind());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100772 }
773
774 /**
775 * Implementation for {@link #createOutputArtifact()} and
776 * {@link #createOutputArtifact(OutputFile)}. This is private so that
777 * {@link #createOutputArtifact(OutputFile)} can have a more specific
778 * signature.
779 */
cparsons0623d3c2018-10-23 16:06:30 -0700780 private Artifact internalCreateOutputArtifact(PathFragment rootRelativePath,
781 Target target, OutputFile.Kind outputFileKind) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000782 Preconditions.checkState(
783 target.getLabel().getPackageIdentifier().equals(getLabel().getPackageIdentifier()),
784 "Creating output artifact for target '%s' in different package than the rule '%s' "
785 + "being analyzed", target.getLabel(), getLabel());
tomlu1cdcdf92018-01-16 11:07:51 -0800786 ArtifactRoot root = getBinOrGenfilesDirectory();
cparsons0623d3c2018-10-23 16:06:30 -0700787
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700788 switch (outputFileKind) {
789 case FILE:
cparsons0623d3c2018-10-23 16:06:30 -0700790 return getDerivedArtifact(rootRelativePath, root);
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700791 case FILESET:
cparsons0623d3c2018-10-23 16:06:30 -0700792 return getAnalysisEnvironment().getFilesetArtifact(rootRelativePath, root);
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700793 default:
794 throw new IllegalStateException();
795 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100796 }
797
798 /**
tomlu1cdcdf92018-01-16 11:07:51 -0800799 * Returns the root of either the "bin" or "genfiles" tree, based on this target and the current
800 * configuration. The choice of which tree to use is based on the rule with which this target
801 * (which must be an OutputFile or a Rule) is associated.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100802 */
David Ostrovskya1388772020-07-08 12:11:01 -0700803 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800804 public ArtifactRoot getBinOrGenfilesDirectory() {
Kristina Chodorowba41c2d2016-10-10 17:21:24 +0000805 return rule.hasBinaryOutput()
Googler0617f2c2020-10-22 08:43:54 -0700806 ? getConfiguration().getBinDirectory(getLabel().getRepository())
807 : getConfiguration().getGenfilesDirectory(getLabel().getRepository());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100808 }
809
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000810 /**
tomlu1cdcdf92018-01-16 11:07:51 -0800811 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
812 * guaranteeing that it never clashes with artifacts created by rules in other packages.
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000813 */
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000814 public Artifact getBinArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000815 return getBinArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000816 }
817
818 public Artifact getBinArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000819 return getPackageRelativeArtifact(
Googler0617f2c2020-10-22 08:43:54 -0700820 relative, getConfiguration().getBinDirectory(getLabel().getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000821 }
822
823 /**
824 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
825 * guaranteeing that it never clashes with artifacts created by rules in other packages.
826 */
827 public Artifact getGenfilesArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000828 return getGenfilesArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000829 }
830
831 public Artifact getGenfilesArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000832 return getPackageRelativeArtifact(
Googler0617f2c2020-10-22 08:43:54 -0700833 relative, getConfiguration().getGenfilesDirectory(getLabel().getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000834 }
835
plfb74df042018-10-31 02:15:10 -0700836 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800837 public Artifact getShareableArtifact(PathFragment rootRelativePath, ArtifactRoot root) {
Lukacs Berki21a04f22015-08-20 13:31:24 +0000838 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root);
839 }
840
asteinb0de45462018-05-17 08:07:12 -0700841 @Override
janakr658d47f2019-05-29 11:11:30 -0700842 public Artifact.DerivedArtifact getPackageRelativeArtifact(
843 PathFragment relative, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700844 return getPackageRelativeArtifact(relative, root, /*contentBasedPath=*/ false);
845 }
846
847 /**
848 * Same as {@link #getPackageRelativeArtifact(PathFragment, ArtifactRoot)} but includes the option
849 * option to use a content-based path for this artifact (see {@link
850 * BuildConfiguration#useContentBasedOutputPaths()}).
851 */
852 private Artifact.DerivedArtifact getPackageRelativeArtifact(
853 PathFragment relative, ArtifactRoot root, boolean contentBasedPath) {
854 return getDerivedArtifact(getPackageDirectory().getRelative(relative), root, contentBasedPath);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000855 }
856
janakr658d47f2019-05-29 11:11:30 -0700857 /**
858 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
859 * guaranteeing that it never clashes with artifacts created by rules in other packages.
860 */
861 public Artifact getPackageRelativeArtifact(String relative, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700862 return getPackageRelativeArtifact(relative, root, /*contentBasedPath=*/ false);
863 }
864
865 /**
866 * Same as {@link #getPackageRelativeArtifact(String, ArtifactRoot)} but includes the option to
867 * use a content-based path for this artifact (see {@link
868 * BuildConfiguration#useContentBasedOutputPaths()}).
869 */
870 private Artifact getPackageRelativeArtifact(
871 String relative, ArtifactRoot root, boolean contentBasedPath) {
872 return getPackageRelativeArtifact(PathFragment.create(relative), root, contentBasedPath);
janakr658d47f2019-05-29 11:11:30 -0700873 }
874
asteinb0de45462018-05-17 08:07:12 -0700875 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000876 public PathFragment getPackageDirectory() {
Googler00217002020-10-27 06:41:26 -0700877 return getLabel()
878 .getPackageIdentifier()
879 .getPackagePath(getConfiguration().isSiblingRepositoryLayout());
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000880 }
881
882 /**
883 * Creates an artifact under a given root with the given root-relative path.
884 *
885 * <p>Verifies that it is in the root-relative directory corresponding to the package of the rule,
886 * thus ensuring that it doesn't clash with other artifacts generated by other rules using this
887 * method.
888 */
Ulf Adams3ab82f72015-09-04 12:10:53 +0000889 @Override
janakr658d47f2019-05-29 11:11:30 -0700890 public Artifact.DerivedArtifact getDerivedArtifact(
891 PathFragment rootRelativePath, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700892 return getDerivedArtifact(rootRelativePath, root, /*contentBasedPath=*/ false);
893 }
894
895 /**
896 * Same as {@link #getDerivedArtifact(PathFragment, ArtifactRoot)} but includes the option to use
897 * a content-based path for this artifact (see {@link
898 * BuildConfiguration#useContentBasedOutputPaths()}).
899 */
900 public Artifact.DerivedArtifact getDerivedArtifact(
901 PathFragment rootRelativePath, ArtifactRoot root, boolean contentBasedPath) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000902 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
903 "Output artifact '%s' not under package directory '%s' for target '%s'",
904 rootRelativePath, getPackageDirectory(), getLabel());
gregce11f3b0e2019-06-07 17:12:06 -0700905 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root, contentBasedPath);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000906 }
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000907
plf441fd752019-02-06 01:28:18 -0800908 @Override
cpeyserac09f0a2018-02-05 09:33:15 -0800909 public SpecialArtifact getTreeArtifact(PathFragment rootRelativePath, ArtifactRoot root) {
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000910 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
911 "Output artifact '%s' not under package directory '%s' for target '%s'",
912 rootRelativePath, getPackageDirectory(), getLabel());
913 return getAnalysisEnvironment().getTreeArtifact(rootRelativePath, root);
914 }
915
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000916 /**
allevato060a4482017-03-30 20:45:52 +0000917 * Creates a tree artifact in a directory that is unique to the package that contains the rule,
918 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
919 */
tomlu1cdcdf92018-01-16 11:07:51 -0800920 public Artifact getPackageRelativeTreeArtifact(PathFragment relative, ArtifactRoot root) {
allevato060a4482017-03-30 20:45:52 +0000921 return getTreeArtifact(getPackageDirectory().getRelative(relative), root);
922 }
923
924 /**
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000925 * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
926 * clashes with artifacts created by other rules.
927 */
928 public Artifact getUniqueDirectoryArtifact(
tomlu1cdcdf92018-01-16 11:07:51 -0800929 String uniqueDirectory, String relative, ArtifactRoot root) {
nharmatab4060b62017-04-04 17:11:39 +0000930 return getUniqueDirectoryArtifact(uniqueDirectory, PathFragment.create(relative), root);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000931 }
932
asteinb0de45462018-05-17 08:07:12 -0700933 @Override
934 public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String relative) {
935 return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
936 }
937
ahumesky4b00ab12018-11-15 16:23:46 -0800938 @Override
939 public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
940 return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
941 }
942
plf727a07d2019-02-01 02:27:35 -0800943 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000944 public Artifact getUniqueDirectoryArtifact(
tomlu1cdcdf92018-01-16 11:07:51 -0800945 String uniqueDirectory, PathFragment relative, ArtifactRoot root) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000946 return getDerivedArtifact(getUniqueDirectory(uniqueDirectory).getRelative(relative), root);
947 }
948
Googler03083852015-12-06 18:31:53 +0000949 /**
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000950 * Returns true iff the rule, or any attached aspect, has an attribute with the given name and
951 * type.
952 */
953 public boolean isAttrDefined(String attrName, Type<?> type) {
Greg Estren7f534232016-12-01 21:38:25 +0000954 return attributes().has(attrName, type);
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000955 }
956
957 /**
Lukacs Berki8bdae762016-07-13 14:58:54 +0000958 * Returns the dependencies through a {@code LABEL_DICT_UNARY} attribute as a map from
959 * a string to a {@link TransitiveInfoCollection}.
960 */
961 public Map<String, TransitiveInfoCollection> getPrerequisiteMap(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +0000962 Preconditions.checkState(attributes().has(attributeName, BuildType.LABEL_DICT_UNARY));
Lukacs Berki8bdae762016-07-13 14:58:54 +0000963
964 ImmutableMap.Builder<String, TransitiveInfoCollection> result = ImmutableMap.builder();
965 Map<String, Label> dict = attributes().get(attributeName, BuildType.LABEL_DICT_UNARY);
966 Map<Label, ConfiguredTarget> labelToDep = new HashMap<>();
janakr9c101402018-03-10 06:48:59 -0800967 for (ConfiguredTargetAndData dep : targetMap.get(attributeName)) {
janakrf3e6f252018-01-18 07:45:12 -0800968 labelToDep.put(dep.getTarget().getLabel(), dep.getConfiguredTarget());
Lukacs Berki8bdae762016-07-13 14:58:54 +0000969 }
970
971 for (Map.Entry<String, Label> entry : dict.entrySet()) {
972 result.put(entry.getKey(), Preconditions.checkNotNull(labelToDep.get(entry.getValue())));
973 }
974
975 return result.build();
976 }
977
978 /**
Googler46b285a2020-03-06 13:33:24 -0800979 * Returns the prerequisites keyed by their configuration transition keys. If the split transition
mjhalupkade47f212018-02-12 12:31:21 -0800980 * is not active (e.g. split() returned an empty list), the key is an empty Optional.
981 */
982 public Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>>
983 getSplitPrerequisites(String attributeName) {
984 return Maps.transformValues(
985 getSplitPrerequisiteConfiguredTargetAndTargets(attributeName),
janakr9c101402018-03-10 06:48:59 -0800986 (ctatList) -> Lists.transform(ctatList, ConfiguredTargetAndData::getConfiguredTarget));
mjhalupkade47f212018-02-12 12:31:21 -0800987 }
988
989 /**
Googler46b285a2020-03-06 13:33:24 -0800990 * Returns the prerequisites keyed by their transition keys. If the split transition is not active
991 * (e.g. split() returned an empty list), the key is an empty Optional.
janakr0758d352018-03-10 20:38:45 -0800992 */
993 public Map<Optional<String>, List<ConfiguredTargetAndData>>
mjhalupkade47f212018-02-12 12:31:21 -0800994 getSplitPrerequisiteConfiguredTargetAndTargets(String attributeName) {
jcater7ba83102020-09-10 11:05:29 -0700995 checkAttributeIsDependency(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100996 // Use an ImmutableListMultimap.Builder here to preserve ordering.
janakr9c101402018-03-10 06:48:59 -0800997 ImmutableListMultimap.Builder<Optional<String>, ConfiguredTargetAndData> result =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100998 ImmutableListMultimap.builder();
jcater0b8280e2020-08-25 08:23:03 -0700999 List<ConfiguredTargetAndData> deps = getPrerequisiteConfiguredTargets(attributeName);
janakr9c101402018-03-10 06:48:59 -08001000 for (ConfiguredTargetAndData t : deps) {
Googler3cc6cc32020-04-29 10:50:38 -07001001 ImmutableList<String> transitionKeys = t.getTransitionKeys();
1002 if (transitionKeys.isEmpty()) {
1003 // The split transition is not active, i.e. does not change build configurations.
Googlerfb55091b2020-09-29 20:41:18 -07001004 // TODO(jungjw): Investigate if we need to do a check here.
Googler3cc6cc32020-04-29 10:50:38 -07001005 return ImmutableMap.of(Optional.absent(), deps);
1006 }
1007 for (String key : transitionKeys) {
1008 result.put(Optional.of(key), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001009 }
1010 }
1011 return Multimaps.asMap(result.build());
1012 }
1013
1014 /**
jcaterf7d726f2020-04-13 10:34:54 -07001015 * Returns the specified provider of the prerequisite referenced by the attribute in the argument.
jcater3a9532d2020-08-26 06:09:28 -07001016 * If the attribute is empty or it does not support the specified provider, returns null.
1017 */
jcater7ba83102020-09-10 11:05:29 -07001018 @Nullable
jcater3a9532d2020-08-26 06:09:28 -07001019 public <C extends TransitiveInfoProvider> C getPrerequisite(
1020 String attributeName, Class<C> provider) {
jcater7ba83102020-09-10 11:05:29 -07001021 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001022 return prerequisite == null ? null : prerequisite.getProvider(provider);
1023 }
1024
1025 /**
1026 * Returns the transitive info collection that feeds into this target through the specified
jcater3a9532d2020-08-26 06:09:28 -07001027 * attribute. Returns null if the attribute is empty.
1028 */
jcater7ba83102020-09-10 11:05:29 -07001029 @Nullable
1030 public TransitiveInfoCollection getPrerequisite(String attributeName) {
1031 ConfiguredTargetAndData result = getPrerequisiteConfiguredTargetAndData(attributeName);
janakr27bb6dd2018-03-10 19:10:00 -08001032 return result == null ? null : result.getConfiguredTarget();
1033 }
1034
1035 /**
1036 * Returns the {@link ConfiguredTargetAndData} that feeds ino this target through the specified
jcater3a9532d2020-08-26 06:09:28 -07001037 * attribute. Returns null if the attribute is empty.
1038 */
jcater7ba83102020-09-10 11:05:29 -07001039 @Nullable
jcater3a9532d2020-08-26 06:09:28 -07001040 public ConfiguredTargetAndData getPrerequisiteConfiguredTargetAndData(String attributeName) {
jcater7ba83102020-09-10 11:05:29 -07001041 checkAttributeIsDependency(attributeName);
jcater0b8280e2020-08-25 08:23:03 -07001042 List<ConfiguredTargetAndData> elements = getPrerequisiteConfiguredTargets(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001043 if (elements.size() > 1) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001044 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
1045 + " produces more than one prerequisite");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001046 }
1047 return elements.isEmpty() ? null : elements.get(0);
1048 }
1049
1050 /**
mjhalupkade47f212018-02-12 12:31:21 -08001051 * For a given attribute, returns all the ConfiguredTargetAndTargets of that attribute. Each
janakr9c101402018-03-10 06:48:59 -08001052 * ConfiguredTargetAndData is keyed by the {@link BuildConfiguration} that created it.
Chris Parsons4aa7c9d2016-04-07 19:29:02 +00001053 */
janakr9c101402018-03-10 06:48:59 -08001054 public ImmutableListMultimap<BuildConfiguration, ConfiguredTargetAndData>
jcaterb979f6e2020-08-25 08:54:38 -07001055 getPrerequisiteCofiguredTargetAndTargetsByConfiguration(String attributeName) {
jcater7ba83102020-09-10 11:05:29 -07001056 checkAttributeIsDependency(attributeName);
jcaterb979f6e2020-08-25 08:54:38 -07001057 List<ConfiguredTargetAndData> ctatCollection = getPrerequisiteConfiguredTargets(attributeName);
janakr9c101402018-03-10 06:48:59 -08001058 ImmutableListMultimap.Builder<BuildConfiguration, ConfiguredTargetAndData> result =
Chris Parsons4aa7c9d2016-04-07 19:29:02 +00001059 ImmutableListMultimap.builder();
janakr9c101402018-03-10 06:48:59 -08001060 for (ConfiguredTargetAndData ctad : ctatCollection) {
janakr163b3922018-03-10 16:24:52 -08001061 result.put(ctad.getConfiguration(), ctad);
Chris Parsons4aa7c9d2016-04-07 19:29:02 +00001062 }
1063 return result.build();
1064 }
1065
1066 /**
dslomovde965ac2017-07-31 21:07:51 +02001067 * For a given attribute, returns all declared provider provided by targets of that attribute.
1068 * Each declared provider is keyed by the {@link BuildConfiguration} under which the provider was
1069 * created.
dslomov4e9fa192017-07-12 14:59:07 +02001070 */
dslomovde965ac2017-07-31 21:07:51 +02001071 public <C extends Info>
1072 ImmutableListMultimap<BuildConfiguration, C> getPrerequisitesByConfiguration(
jcater3a9532d2020-08-26 06:09:28 -07001073 String attributeName, BuiltinProvider<C> provider) {
jcater7ba83102020-09-10 11:05:29 -07001074 checkAttributeIsDependency(attributeName);
jcaterb979f6e2020-08-25 08:54:38 -07001075 List<ConfiguredTargetAndData> ctatCollection = getPrerequisiteConfiguredTargets(attributeName);
dslomov4e9fa192017-07-12 14:59:07 +02001076 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
1077 ImmutableListMultimap.builder();
jcaterb979f6e2020-08-25 08:54:38 -07001078 for (ConfiguredTargetAndData prerequisite : ctatCollection) {
janakr12b78fe2018-03-10 18:06:56 -08001079 C prerequisiteProvider = prerequisite.getConfiguredTarget().get(provider);
dslomov4e9fa192017-07-12 14:59:07 +02001080 if (prerequisiteProvider != null) {
1081 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
1082 }
1083 }
1084 return result.build();
1085 }
1086
1087 /**
jcaterf7d726f2020-04-13 10:34:54 -07001088 * For a given attribute, returns all {@link TransitiveInfoCollection}s provided by targets of
1089 * that attribute. Each {@link TransitiveInfoCollection} is keyed by the {@link
1090 * BuildConfiguration} under which the collection was created.
Chris Parsons0d7f0412016-04-29 20:35:44 +00001091 */
1092 public ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection>
jcaterb979f6e2020-08-25 08:54:38 -07001093 getPrerequisitesByConfiguration(String attributeName) {
jcater7ba83102020-09-10 11:05:29 -07001094 checkAttributeIsDependency(attributeName);
jcaterb979f6e2020-08-25 08:54:38 -07001095 List<ConfiguredTargetAndData> ctatCollection = getPrerequisiteConfiguredTargets(attributeName);
Chris Parsons0d7f0412016-04-29 20:35:44 +00001096 ImmutableListMultimap.Builder<BuildConfiguration, TransitiveInfoCollection> result =
1097 ImmutableListMultimap.builder();
jcaterb979f6e2020-08-25 08:54:38 -07001098 for (ConfiguredTargetAndData prerequisite : ctatCollection) {
janakr12b78fe2018-03-10 18:06:56 -08001099 result.put(prerequisite.getConfiguration(), prerequisite.getConfiguredTarget());
Chris Parsons0d7f0412016-04-29 20:35:44 +00001100 }
1101 return result.build();
1102 }
1103
1104 /**
cparsonsb35c0a42018-08-20 11:37:41 -07001105 * Returns the list of transitive info collections that feed into this target through the
jcater3a9532d2020-08-26 06:09:28 -07001106 * specified attribute.
1107 */
1108 public List<? extends TransitiveInfoCollection> getPrerequisites(String attributeName) {
jcater1ae143b2020-09-10 11:38:09 -07001109 if (!attributes().has(attributeName)) {
1110 return ImmutableList.of();
1111 }
1112
1113 List<ConfiguredTargetAndData> prerequisiteConfiguredTargets;
Googler09cd1fc2021-04-05 17:57:11 -07001114 // android_binary, android_test, and android_binary_internal override deps to use a split
1115 // transition.
jcater23b0b8a2020-09-11 12:06:02 -07001116 if ((getRule().getRuleClass().equals("android_binary")
Googler09cd1fc2021-04-05 17:57:11 -07001117 || getRule().getRuleClass().equals("android_test")
1118 || getRule().getRuleClass().equals("android_binary_internal"))
jcater1ae143b2020-09-10 11:38:09 -07001119 && attributeName.equals("deps")
1120 && attributes().getAttributeDefinition(attributeName).getTransitionFactory().isSplit()) {
1121 // TODO(b/168038145): Restore legacy behavior of returning the prerequisites from the first
1122 // portion of the split transition.
1123 // Callers should be identified, cleaned up, and this check removed.
1124 Map<Optional<String>, List<ConfiguredTargetAndData>> map =
1125 getSplitPrerequisiteConfiguredTargetAndTargets(attributeName);
1126 prerequisiteConfiguredTargets =
1127 map.isEmpty() ? ImmutableList.of() : map.entrySet().iterator().next().getValue();
1128 } else {
1129 prerequisiteConfiguredTargets = getPrerequisiteConfiguredTargets(attributeName);
1130 }
1131
cparsonsb35c0a42018-08-20 11:37:41 -07001132 return Lists.transform(
jcater1ae143b2020-09-10 11:38:09 -07001133 prerequisiteConfiguredTargets, ConfiguredTargetAndData::getConfiguredTarget);
cparsonsb35c0a42018-08-20 11:37:41 -07001134 }
1135
1136 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001137 * Returns all the providers of the specified type that are listed under the specified attribute
1138 * of this target in the BUILD file.
1139 */
ulfjack6c3908c2019-12-18 05:03:36 -08001140 public <C extends TransitiveInfoProvider> List<C> getPrerequisites(
jcater3a9532d2020-08-26 06:09:28 -07001141 String attributeName, Class<C> classType) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001142 AnalysisUtils.checkProvider(classType);
jcater7ba83102020-09-10 11:05:29 -07001143 return AnalysisUtils.getProviders(getPrerequisites(attributeName), classType);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001144 }
1145
1146 /**
gregceca48e9a2020-04-14 08:54:38 -07001147 * Returns all the declared providers (native and Starlark) for the specified constructor under
1148 * the specified attribute of this target in the BUILD file.
Sergio Campamafd931432016-12-09 21:47:35 +00001149 */
ulfjack6c3908c2019-12-18 05:03:36 -08001150 public <T extends Info> List<T> getPrerequisites(
jcater3a9532d2020-08-26 06:09:28 -07001151 String attributeName, BuiltinProvider<T> starlarkKey) {
jcater7ba83102020-09-10 11:05:29 -07001152 return AnalysisUtils.getProviders(getPrerequisites(attributeName), starlarkKey);
cparsons2d67cf92018-05-24 14:02:09 -07001153 }
1154
1155 /**
gregceca48e9a2020-04-14 08:54:38 -07001156 * Returns the declared provider (native and Starlark) for the specified constructor under the
Sergio Campamae8cecd92016-12-13 18:49:28 +00001157 * specified attribute of this target in the BUILD file. May return null if there is no
1158 * TransitiveInfoCollection under the specified attribute.
1159 */
1160 @Nullable
jcater3a9532d2020-08-26 06:09:28 -07001161 public <T extends Info> T getPrerequisite(String attributeName, BuiltinProvider<T> starlarkKey) {
jcater7ba83102020-09-10 11:05:29 -07001162 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName);
gregce0503fee2020-06-11 09:22:27 -07001163 return prerequisite == null ? null : prerequisite.get(starlarkKey);
cparsonsabeb8512018-06-11 12:44:06 -07001164 }
cparsonsabeb8512018-06-11 12:44:06 -07001165 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001166 * Returns all the providers of the specified type that are listed under the specified attribute
1167 * of this target in the BUILD file, and that contain the specified provider.
1168 */
jcaterf7d726f2020-04-13 10:34:54 -07001169 public <C extends TransitiveInfoProvider>
1170 Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
jcater3a9532d2020-08-26 06:09:28 -07001171 String attributeName, Class<C> classType) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001172 AnalysisUtils.checkProvider(classType);
jcater7ba83102020-09-10 11:05:29 -07001173 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName), classType);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001174 }
1175
1176 /**
dslomov73527c32017-07-27 17:35:46 +02001177 * Returns all the providers of the specified type that are listed under the specified attribute
1178 * of this target in the BUILD file, and that contain the specified provider.
1179 */
dslomovde965ac2017-07-31 21:07:51 +02001180 public <C extends Info> Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
jcater3a9532d2020-08-26 06:09:28 -07001181 String attributeName, BuiltinProvider<C> classType) {
jcater7ba83102020-09-10 11:05:29 -07001182 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName), classType);
Googler7ac77232019-06-04 14:26:47 -07001183 }
1184
1185 /**
jcaterf7d726f2020-04-13 10:34:54 -07001186 * Returns the prerequisite referred to by the specified attribute. Also checks whether the
1187 * attribute is marked as executable and that the target referred to can actually be executed.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001188 *
jcater3a9532d2020-08-26 06:09:28 -07001189 * @param attributeName the name of the attribute
1190 * @return the {@link FilesToRunProvider} interface of the prerequisite.
1191 */
1192 @Nullable
1193 public FilesToRunProvider getExecutablePrerequisite(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +00001194 Attribute ruleDefinition = attributes().getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001195
1196 if (ruleDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001197 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001198 + " is not defined");
1199 }
1200 if (!ruleDefinition.isExecutable()) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001201 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001202 + " is not configured to be executable");
1203 }
1204
jcater7ba83102020-09-10 11:05:29 -07001205 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001206 if (prerequisite == null) {
1207 return null;
1208 }
1209
1210 FilesToRunProvider result = prerequisite.getProvider(FilesToRunProvider.class);
1211 if (result == null || result.getExecutable() == null) {
1212 attributeError(
1213 attributeName, prerequisite.getLabel() + " does not refer to a valid executable target");
1214 }
1215 return result;
1216 }
1217
ulfjack08ff9b82017-09-28 04:08:06 -04001218 public void initConfigurationMakeVariableContext(
1219 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
brandjon96e223a2021-02-01 09:05:36 -08001220 Preconditions.checkState(
1221 configurationMakeVariableContext == null,
1222 "Attempted to init an already initialized Make var context (did you call"
1223 + " initConfigurationMakeVariableContext() after accessing ctx.var?)");
ulfjack08ff9b82017-09-28 04:08:06 -04001224 configurationMakeVariableContext =
1225 new ConfigurationMakeVariableContext(
1226 this, getRule().getPackage(), getConfiguration(), makeVariableSuppliers);
1227 }
1228
1229 public void initConfigurationMakeVariableContext(MakeVariableSupplier... makeVariableSuppliers) {
1230 initConfigurationMakeVariableContext(ImmutableList.copyOf(makeVariableSuppliers));
1231 }
1232
ulfjack01bf32e2017-11-02 17:50:07 -04001233 public Expander getExpander(TemplateContext templateContext) {
gregce31e44792020-04-27 09:10:40 -07001234 Expander expander = new Expander(this, templateContext);
1235 makeVariableExpanders.add(expander);
1236 return expander;
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001237 }
1238
ulfjack07860132017-09-29 08:59:44 -04001239 public Expander getExpander() {
gregce31e44792020-04-27 09:10:40 -07001240 Expander expander = new Expander(this, getConfigurationMakeVariableContext());
1241 makeVariableExpanders.add(expander);
1242 return expander;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001243 }
1244
Googlera45a8e02019-05-13 11:17:02 -07001245 public Expander getExpander(ImmutableMap<Label, ImmutableCollection<Artifact>> labelMap) {
gregce31e44792020-04-27 09:10:40 -07001246 Expander expander = new Expander(this, getConfigurationMakeVariableContext(), labelMap);
1247 makeVariableExpanders.add(expander);
1248 return expander;
Googlera45a8e02019-05-13 11:17:02 -07001249 }
1250
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001251 /**
ulfjack08ff9b82017-09-28 04:08:06 -04001252 * Returns a cached context that maps Make variable names (string) to values (string) without any
1253 * extra {@link MakeVariableSupplier}.
brandjon96e223a2021-02-01 09:05:36 -08001254 *
1255 * <p>CAUTION: If there's no context, this will initialize the context with no
1256 * MakeVariableSuppliers. Call {@link #initConfigurationMakeVariableContext} first if you want to
1257 * register suppliers.
hlopkoa4778052017-05-26 11:37:28 +02001258 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001259 public ConfigurationMakeVariableContext getConfigurationMakeVariableContext() {
1260 if (configurationMakeVariableContext == null) {
ulfjack08ff9b82017-09-28 04:08:06 -04001261 initConfigurationMakeVariableContext(ImmutableList.<MakeVariableSupplier>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001262 }
1263 return configurationMakeVariableContext;
1264 }
1265
brandjon2e34f1a2020-12-17 16:42:00 -08001266 public StarlarkSemantics getStarlarkSemantics() {
1267 return starlarkSemantics;
1268 }
1269
1270 private StarlarkThread createStarlarkThread(String toolsRepository, Mutability mutability) {
brandjonbfd332e2020-12-17 14:56:04 -08001271 AnalysisEnvironment env = getAnalysisEnvironment();
1272 StarlarkThread thread = new StarlarkThread(mutability, starlarkSemantics);
1273 thread.setPrintHandler(Event.makeDebugPrintHandler(env.getEventHandler()));
1274 new BazelStarlarkContext(
1275 BazelStarlarkContext.Phase.ANALYSIS,
1276 toolsRepository,
1277 /*fragmentNameToClass=*/ null,
1278 getTarget().getPackage().getRepositoryMapping(),
1279 /*convertedLabelsInPackage=*/ new HashMap<>(),
1280 getSymbolGenerator(),
1281 getLabel())
1282 .storeInThread(thread);
1283 return thread;
1284 }
1285
1286 public StarlarkThread getStarlarkThread() {
1287 return starlarkThread;
1288 }
1289
1290 /**
brandjonf1cc4dd2021-02-01 08:53:40 -08001291 * Initializes the StarlarkRuleContext for use and returns it.
1292 *
1293 * <p>Throws RuleErrorException on failure.
1294 */
1295 public StarlarkRuleContext initStarlarkRuleContext() throws RuleErrorException {
1296 Preconditions.checkState(starlarkRuleContext == null);
1297 AspectDescriptor descriptor =
1298 aspects.isEmpty() ? null : Iterables.getLast(aspects).getDescriptor();
brandjon4f331eb2021-02-01 09:09:39 -08001299 this.starlarkRuleContext = new StarlarkRuleContext(this, descriptor);
brandjonf1cc4dd2021-02-01 08:53:40 -08001300 return starlarkRuleContext;
1301 }
1302
1303 public StarlarkRuleContext getStarlarkRuleContext() {
1304 Preconditions.checkNotNull(starlarkRuleContext, "Must call initStarlarkRuleContext() first");
1305 return starlarkRuleContext;
1306 }
1307
1308 /**
brandjon4f331eb2021-02-01 09:09:39 -08001309 * Retrieves the {@code @_builtins}-defined Starlark object registered in the {@code
1310 * exported_to_java} mapping under the given name.
1311 *
1312 * <p>Reports and raises a rule error if no symbol by that name is defined.
1313 */
1314 public Object getStarlarkDefinedBuiltin(String name)
1315 throws RuleErrorException, InterruptedException {
1316 Object result = getAnalysisEnvironment().getStarlarkDefinedBuiltins().get(name);
1317 if (result == null) {
1318 throwWithRuleError(
1319 String.format(
1320 "(Internal error) No symbol named '%s' defined in the @_builtins exported_to_java"
1321 + " dict",
1322 name));
1323 }
1324 return result;
1325 }
1326
1327 /**
1328 * Calls a Starlark function in this rule's Starlark thread with the given positional and keyword
1329 * arguments. On failure, calls {@link #throwWithRuleError} with the Starlark stack trace.
1330 *
1331 * <p>This convenience method avoids the need to catch EvalException when the failure would just
1332 * immediately terminate rule analysis anyway.
1333 */
1334 public Object callStarlarkOrThrowRuleError(
1335 Object func, List<Object> args, Map<String, Object> kwargs)
1336 throws RuleErrorException, InterruptedException {
1337 try {
1338 return Starlark.call(starlarkThread, func, args, kwargs);
1339 } catch (EvalException e) {
1340 throwWithRuleError(e.getMessageWithStack());
1341 // Pacify compiler.
1342 return null;
1343 }
1344 }
1345
1346 /**
brandjonbfd332e2020-12-17 14:56:04 -08001347 * Prepares Starlark objects created during this target's analysis for use by others. Freezes
1348 * mutability, clears expensive references.
1349 */
1350 @Override
1351 public void close() {
1352 starlarkThread.mutability().freeze();
brandjonf1cc4dd2021-02-01 08:53:40 -08001353 if (starlarkRuleContext != null) {
1354 starlarkRuleContext.nullify();
1355 }
brandjonbfd332e2020-12-17 14:56:04 -08001356 }
1357
John Cater13263f72017-05-24 19:06:47 +02001358 @Nullable
John Catercdfa9ca2019-04-05 12:32:09 -07001359 public ResolvedToolchainContext getToolchainContext() {
juliexxiab5f9d742020-04-09 13:07:13 -07001360 return toolchainContexts == null ? null : toolchainContexts.getDefaultToolchainContext();
1361 }
1362
1363 @Nullable
juliexxiaff580812020-04-30 15:01:09 -07001364 private ResolvedToolchainContext getToolchainContext(String execGroup) {
1365 return toolchainContexts == null ? null : toolchainContexts.getToolchainContext(execGroup);
1366 }
1367
1368 public boolean hasToolchainContext(String execGroup) {
1369 return toolchainContexts != null && toolchainContexts.hasToolchainContext(execGroup);
1370 }
1371
1372 @Nullable
juliexxia0a0a13b2020-04-21 15:55:00 -07001373 public ToolchainCollection<ResolvedToolchainContext> getToolchainContexts() {
juliexxiab5f9d742020-04-09 13:07:13 -07001374 return toolchainContexts;
John Catereca28402017-05-17 21:44:12 +02001375 }
1376
jcater0a1e9eb2019-12-17 09:58:38 -08001377 public boolean targetPlatformHasConstraint(ConstraintValueInfo constraintValue) {
juliexxiacede76b2020-09-23 13:49:34 -07001378 if (toolchainContexts == null || toolchainContexts.getTargetPlatform() == null) {
jcater0a1e9eb2019-12-17 09:58:38 -08001379 return false;
1380 }
juliexxiab5f9d742020-04-09 13:07:13 -07001381 // All toolchain contexts should have the same target platform so we access via the default.
juliexxiacede76b2020-09-23 13:49:34 -07001382 return toolchainContexts.getTargetPlatform().constraints().hasConstraintValue(constraintValue);
jcater0a1e9eb2019-12-17 09:58:38 -08001383 }
1384
jcater802551e2020-04-15 09:59:58 -07001385 public ConstraintSemantics<RuleContext> getConstraintSemantics() {
gregce6acfe4e2018-05-25 08:38:39 -07001386 return constraintSemantics;
1387 }
1388
gregce31e44792020-04-27 09:10:40 -07001389 /**
1390 * Returns the configuration fragments this rule uses.
1391 *
1392 * <p>Returned results are alphabetically ordered.
1393 */
1394 public ImmutableSortedSet<String> getRequiredConfigFragments() {
1395 ImmutableSortedSet.Builder<String> ans = ImmutableSortedSet.naturalOrder();
1396 ans.addAll(requiredConfigFragments);
1397 for (Expander makeVariableExpander : makeVariableExpanders) {
1398 for (String makeVariable : makeVariableExpander.lookedUpVariables()) {
1399 // User-defined make values may be set either in "--define foo=bar" or in a vardef in the
1400 // rule's package. Both are equivalent for these purposes, since in both cases setting
1401 // "--define foo=bar" impacts the rule's output.
1402 if (getRule().getPackage().getMakeEnvironment().containsKey(makeVariable)
1403 || getConfiguration().getCommandLineBuildVariables().containsKey(makeVariable)) {
1404 ans.add("--define:" + makeVariable);
1405 }
1406 }
1407 }
1408 return ans.build();
gregce966dc232019-10-18 15:34:07 -07001409 }
1410
John Caterf1e0d342021-03-05 13:44:19 -08001411 private ImmutableTable<String, String, String> parseExecProperties(
juliexxia3eb806e2020-07-15 08:42:34 -07001412 Map<String, String> execProperties) throws InvalidExecGroupException {
1413 if (execProperties.isEmpty()) {
John Caterf1e0d342021-03-05 13:44:19 -08001414 return ImmutableTable.of();
Googlerb5082462019-08-26 14:28:09 -07001415 } else {
juliexxia6fe70c22020-05-18 14:38:42 -07001416 return parseExecProperties(
Yuvald0676692021-03-05 09:53:44 -08001417 execProperties, toolchainContexts == null ? null : toolchainContexts.getExecGroups());
Googlerb5082462019-08-26 14:28:09 -07001418 }
1419 }
1420
juliexxia6fe70c22020-05-18 14:38:42 -07001421 /**
1422 * Parse raw exec properties attribute value into a map of exec group names to their properties.
1423 * The raw map can have keys of two forms: (1) 'property' and (2) 'exec_group_name.property'. The
Yuvald0676692021-03-05 09:53:44 -08001424 * former get parsed into the default exec group, the latter get parsed into their relevant exec
1425 * groups.
juliexxia6fe70c22020-05-18 14:38:42 -07001426 */
John Caterf1e0d342021-03-05 13:44:19 -08001427 private static ImmutableTable<String, String, String> parseExecGroups(
Yuvald0676692021-03-05 09:53:44 -08001428 Map<String, String> rawExecProperties) {
John Caterf1e0d342021-03-05 13:44:19 -08001429 ImmutableTable.Builder<String, String, String> execProperties = ImmutableTable.builder();
juliexxia6fe70c22020-05-18 14:38:42 -07001430 for (Map.Entry<String, String> execProperty : rawExecProperties.entrySet()) {
1431 String rawProperty = execProperty.getKey();
1432 int delimiterIndex = rawProperty.indexOf('.');
1433 if (delimiterIndex == -1) {
John Caterf1e0d342021-03-05 13:44:19 -08001434 execProperties.put(DEFAULT_EXEC_GROUP_NAME, rawProperty, execProperty.getValue());
juliexxia6fe70c22020-05-18 14:38:42 -07001435 } else {
1436 String execGroup = rawProperty.substring(0, delimiterIndex);
1437 String property = rawProperty.substring(delimiterIndex + 1);
John Caterf1e0d342021-03-05 13:44:19 -08001438 execProperties.put(execGroup, property, execProperty.getValue());
juliexxia6fe70c22020-05-18 14:38:42 -07001439 }
John Cater15c90b32017-12-18 08:34:40 -08001440 }
John Caterf1e0d342021-03-05 13:44:19 -08001441 return execProperties.build();
Yuvald0676692021-03-05 09:53:44 -08001442 }
1443
1444 /**
1445 * Parse raw exec properties attribute value into a map of exec group names to their properties.
1446 * If given a set of exec groups, validates all the exec groups in the map are applicable to the
1447 * action.
1448 */
John Caterf1e0d342021-03-05 13:44:19 -08001449 private static ImmutableTable<String, String, String> parseExecProperties(
Yuvald0676692021-03-05 09:53:44 -08001450 Map<String, String> rawExecProperties, @Nullable Set<String> execGroups)
1451 throws InvalidExecGroupException {
John Caterf1e0d342021-03-05 13:44:19 -08001452 ImmutableTable<String, String, String> consolidatedProperties =
1453 parseExecGroups(rawExecProperties);
Yuvald0676692021-03-05 09:53:44 -08001454 if (execGroups != null) {
John Caterf1e0d342021-03-05 13:44:19 -08001455 for (String execGroupName : consolidatedProperties.rowKeySet()) {
Yuvald0676692021-03-05 09:53:44 -08001456 if (!execGroupName.equals(DEFAULT_EXEC_GROUP_NAME) && !execGroups.contains(execGroupName)) {
1457 throw new InvalidExecGroupException(
1458 String.format(
1459 "Tried to set properties for non-existent exec group '%s'.", execGroupName));
1460 }
1461 }
1462 }
juliexxia6fe70c22020-05-18 14:38:42 -07001463
John Caterf1e0d342021-03-05 13:44:19 -08001464 return consolidatedProperties;
John Cater15c90b32017-12-18 08:34:40 -08001465 }
1466
juliexxia6fe70c22020-05-18 14:38:42 -07001467 /**
1468 * Gets the combined exec properties of the given exec group and the target's exec properties. If
1469 * a property is set in both, the exec group properties take precedence. If a non-existent exec
1470 * group is passed in, just returns the target's exec properties.
1471 *
1472 * @param execGroup group whose properties to retrieve
1473 * @param execProperties Map of exec group name to map of properties and values
1474 */
1475 private static ImmutableMap<String, String> getExecProperties(
John Caterf1e0d342021-03-05 13:44:19 -08001476 String execGroup, ImmutableTable<String, String, String> execProperties) {
1477 if (!execProperties.containsRow(execGroup) || execGroup.equals(DEFAULT_EXEC_GROUP_NAME)) {
1478 return execProperties.row(DEFAULT_EXEC_GROUP_NAME);
juliexxiaff580812020-04-30 15:01:09 -07001479 }
juliexxia6fe70c22020-05-18 14:38:42 -07001480
1481 // Use a HashMap to build here because we expect duplicate keys to happen
1482 // (and rewrite previous entries).
1483 Map<String, String> targetAndGroupProperties =
John Caterf1e0d342021-03-05 13:44:19 -08001484 new HashMap<>(execProperties.row(DEFAULT_EXEC_GROUP_NAME));
1485 targetAndGroupProperties.putAll(execProperties.row(execGroup));
juliexxia6fe70c22020-05-18 14:38:42 -07001486 return ImmutableMap.copyOf(targetAndGroupProperties);
1487 }
1488
1489 /** An error for when the user tries to access an non-existent exec group */
1490 public static final class InvalidExecGroupException extends Exception
1491 implements SaneAnalysisException {
1492 InvalidExecGroupException(String message) {
1493 super(message);
1494 }
mschaller859c9ac2020-09-25 16:09:19 -07001495
1496 @Override
1497 public DetailedExitCode getDetailedExitCode() {
1498 return DetailedExitCode.of(
1499 FailureDetail.newBuilder()
1500 .setMessage(getMessage())
1501 .setAnalysis(Analysis.newBuilder().setCode(Code.EXEC_GROUP_MISSING))
1502 .build());
1503 }
juliexxia6fe70c22020-05-18 14:38:42 -07001504 }
1505
jcater7ba83102020-09-10 11:05:29 -07001506 private void checkAttributeIsDependency(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +00001507 Attribute attributeDefinition = attributes.getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001508 if (attributeDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001509 throw new IllegalStateException(getRule().getLocation() + ": " + getRuleClassNameForLogging()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001510 + " attribute " + attributeName + " is not defined");
1511 }
Michael Staiba751f922017-02-14 15:50:04 +00001512 if (attributeDefinition.getType().getLabelClass() != LabelClass.DEPENDENCY) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001513 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001514 + " is not a label type attribute");
1515 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001516 }
1517
juliexxia6fe70c22020-05-18 14:38:42 -07001518 @Override
1519 @Nullable
1520 public PlatformInfo getExecutionPlatform() {
1521 if (getToolchainContext() == null) {
1522 return null;
1523 }
1524 return getToolchainContext().executionPlatform();
1525 }
1526
1527 @Override
1528 @Nullable
1529 public PlatformInfo getExecutionPlatform(String execGroup) {
1530 if (getToolchainContexts() == null) {
1531 return null;
1532 }
1533 ResolvedToolchainContext toolchainContext = getToolchainContext(execGroup);
1534 return toolchainContext == null ? null : toolchainContext.executionPlatform();
1535 }
1536
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001537 /**
jcaterf7d726f2020-04-13 10:34:54 -07001538 * For the specified attribute "attributeName" (which must be of type list(label)), resolve all
1539 * the labels into ConfiguredTargets (for the configuration appropriate to the attribute) and
1540 * return their build artifacts as a {@link PrerequisiteArtifacts} instance.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001541 *
1542 * @param attributeName the name of the attribute to traverse
1543 */
jcater3a9532d2020-08-26 06:09:28 -07001544 public PrerequisiteArtifacts getPrerequisiteArtifacts(String attributeName) {
jcater7ba83102020-09-10 11:05:29 -07001545 return PrerequisiteArtifacts.get(this, attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001546 }
1547
1548 /**
jcaterf7d726f2020-04-13 10:34:54 -07001549 * For the specified attribute "attributeName" (which must be of type label), resolves the
1550 * ConfiguredTarget and returns its single build artifact.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001551 *
jcaterf7d726f2020-04-13 10:34:54 -07001552 * <p>If the attribute is optional, has no default and was not specified, then null will be
1553 * returned. Note also that null is returned (and an attribute error is raised) if there wasn't
1554 * exactly one build artifact for the target.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001555 */
jcater3a9532d2020-08-26 06:09:28 -07001556 public Artifact getPrerequisiteArtifact(String attributeName) {
jcater7ba83102020-09-10 11:05:29 -07001557 TransitiveInfoCollection target = getPrerequisite(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001558 return transitiveInfoCollectionToArtifact(attributeName, target);
1559 }
1560
1561 /**
jcater7ba83102020-09-10 11:05:29 -07001562 * Equivalent to getPrerequisiteArtifact(), but also asserts that host-configuration is
1563 * appropriate for the specified attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001564 */
jcater7ba83102020-09-10 11:05:29 -07001565 // TODO(b/165916637): Fix callers to this method to use getPrerequisiteArtifact instead.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001566 public Artifact getHostPrerequisiteArtifact(String attributeName) {
jcater7ba83102020-09-10 11:05:29 -07001567 return getPrerequisiteArtifact(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001568 }
1569
1570 private Artifact transitiveInfoCollectionToArtifact(
1571 String attributeName, TransitiveInfoCollection target) {
1572 if (target != null) {
ulfjack8d8f62f2019-12-05 15:03:53 -08001573 NestedSet<Artifact> artifacts = target.getProvider(FileProvider.class).getFilesToBuild();
1574 if (artifacts.isSingleton()) {
1575 return artifacts.getSingleton();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001576 } else {
1577 attributeError(attributeName, target.getLabel() + " expected a single artifact");
1578 }
1579 }
1580 return null;
1581 }
1582
1583 /**
1584 * Returns the sole file in the "srcs" attribute. Reports an error and
1585 * (possibly) returns null if "srcs" does not identify a single file of the
1586 * expected type.
1587 */
1588 public Artifact getSingleSource(String fileTypeName) {
jcater7ba83102020-09-10 11:05:29 -07001589 List<Artifact> srcs = PrerequisiteArtifacts.get(this, "srcs").list();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001590 switch (srcs.size()) {
1591 case 0 : // error already issued by getSrc()
1592 return null;
1593 case 1 : // ok
1594 return Iterables.getOnlyElement(srcs);
1595 default :
1596 attributeError("srcs", "only a single " + fileTypeName + " is allowed here");
1597 return srcs.get(0);
1598 }
1599 }
1600
1601 public Artifact getSingleSource() {
Michael Staib8824d5e2016-01-20 21:37:05 +00001602 return getSingleSource(getRuleClassNameForLogging() + " source file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001603 }
1604
1605 /**
1606 * Returns a path fragment qualified by the rule name and unique fragment to
1607 * disambiguate artifacts produced from the source file appearing in
1608 * multiple rules.
1609 *
1610 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1611 */
1612 public final PathFragment getUniqueDirectory(String fragment) {
nharmata5e924af2017-05-02 18:16:23 +02001613 return getUniqueDirectory(PathFragment.create(fragment));
1614 }
1615
1616 /**
David Ostrovskya1388772020-07-08 12:11:01 -07001617 * Returns a path fragment qualified by the rule name and unique fragment to disambiguate
1618 * artifacts produced from the source file appearing in multiple rules.
nharmata5e924af2017-05-02 18:16:23 +02001619 *
1620 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1621 */
David Ostrovskya1388772020-07-08 12:11:01 -07001622 @Override
nharmata5e924af2017-05-02 18:16:23 +02001623 public final PathFragment getUniqueDirectory(PathFragment fragment) {
Googler7b644a62020-10-21 11:56:33 -07001624 return AnalysisUtils.getUniqueDirectory(
1625 getLabel(), fragment, getConfiguration().isSiblingRepositoryLayout());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001626 }
1627
1628 /**
1629 * Check that all targets that were specified as sources are from the same
1630 * package as this rule. Output a warning or an error for every target that is
1631 * imported from a different package.
1632 */
1633 public void checkSrcsSamePackage(boolean onlyWarn) {
1634 PathFragment packageName = getLabel().getPackageFragment();
jcater7ba83102020-09-10 11:05:29 -07001635 for (Artifact srcItem : PrerequisiteArtifacts.get(this, "srcs").list()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001636 if (!srcItem.isSourceArtifact()) {
1637 // In theory, we should not do this check. However, in practice, we
1638 // have a couple of rules that do not obey the "srcs must contain
1639 // files and only files" rule. Thus, we are stuck with this hack here :(
1640 continue;
1641 }
1642 Label associatedLabel = srcItem.getOwner();
1643 PathFragment itemPackageName = associatedLabel.getPackageFragment();
1644 if (!itemPackageName.equals(packageName)) {
1645 String message = "please do not import '" + associatedLabel + "' directly. "
1646 + "You should either move the file to this package or depend on "
1647 + "an appropriate rule there";
1648 if (onlyWarn) {
1649 attributeWarning("srcs", message);
1650 } else {
1651 attributeError("srcs", message);
1652 }
1653 }
1654 }
1655 }
1656
1657
1658 /**
1659 * Returns the label to which the {@code NODEP_LABEL} attribute
1660 * {@code attrName} refers, checking that it is a valid label, and that it is
1661 * referring to a local target. Reports a warning otherwise.
1662 */
1663 public Label getLocalNodepLabelAttribute(String attrName) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001664 Label label = attributes().get(attrName, BuildType.NODEP_LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001665 if (label == null) {
1666 return null;
1667 }
1668
1669 if (!getTarget().getLabel().getPackageFragment().equals(label.getPackageFragment())) {
1670 attributeWarning(attrName, "does not reference a local rule");
1671 }
1672
1673 return label;
1674 }
1675
asteinb0de45462018-05-17 08:07:12 -07001676 @Override
Florian Weikert4b67d4f2015-09-14 13:35:34 +00001677 public Artifact getImplicitOutputArtifact(ImplicitOutputsFunction function)
1678 throws InterruptedException {
gregce11f3b0e2019-06-07 17:12:06 -07001679 return getImplicitOutputArtifact(function, /*contentBasedPath=*/ false);
1680 }
1681
1682 /**
1683 * Same as {@link #getImplicitOutputArtifact(ImplicitOutputsFunction)} but includes the option to
1684 * use a content-based path for this artifact (see {@link
1685 * BuildConfiguration#useContentBasedOutputPaths()}).
1686 */
1687 public Artifact getImplicitOutputArtifact(
1688 ImplicitOutputsFunction function, boolean contentBasedPath) throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001689 Iterable<String> result;
1690 try {
vladmos076977e2017-12-02 14:15:32 -08001691 result =
1692 function.getImplicitOutputs(
1693 getAnalysisEnvironment().getEventHandler(), RawAttributeMapper.of(rule));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001694 } catch (EvalException e) {
gregceca48e9a2020-04-14 08:54:38 -07001695 // It's ok as long as we don't use this method from Starlark.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001696 throw new IllegalStateException(e);
1697 }
gregce11f3b0e2019-06-07 17:12:06 -07001698 return getImplicitOutputArtifact(Iterables.getOnlyElement(result), contentBasedPath);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001699 }
1700
gregceca48e9a2020-04-14 08:54:38 -07001701 /** Only use from Starlark. Returns the implicit output artifact for a given output path. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001702 public Artifact getImplicitOutputArtifact(String path) {
gregce11f3b0e2019-06-07 17:12:06 -07001703 return getImplicitOutputArtifact(path, /*contentBasedPath=*/ false);
1704 }
1705
1706 /**
1707 * Same as {@link #getImplicitOutputArtifact(String)} but includes the option to use a a
1708 * content-based path for this artifact (see {@link
1709 * BuildConfiguration#useContentBasedOutputPaths()}).
1710 */
brandjond2582632021-01-29 16:10:58 -08001711 // TODO(bazel-team): Consider removing contentBasedPath stuff, which is unused as of 18 months
1712 // after its introduction in cl/252148134.
gregce11f3b0e2019-06-07 17:12:06 -07001713 private Artifact getImplicitOutputArtifact(String path, boolean contentBasedPath) {
1714 return getPackageRelativeArtifact(path, getBinOrGenfilesDirectory(), contentBasedPath);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001715 }
1716
1717 /**
jcater7ba83102020-09-10 11:05:29 -07001718 * Convenience method to return a configured target for the "compiler" attribute. Allows caller to
1719 * decide whether a warning should be printed if the "compiler" attribute is not set to the
1720 * default value.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001721 *
jcater7ba83102020-09-10 11:05:29 -07001722 * @param warnIfNotDefault if true, print a warning if the value for the "compiler" attribute is
1723 * set to something other than the default
1724 * @return a ConfiguredTarget for the "compiler" attribute
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001725 */
1726 public final FilesToRunProvider getCompiler(boolean warnIfNotDefault) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001727 Label label = attributes().get("compiler", BuildType.LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001728 if (warnIfNotDefault && !label.equals(getRule().getAttrDefaultValue("compiler"))) {
1729 attributeWarning("compiler", "setting the compiler is strongly discouraged");
1730 }
jcater7ba83102020-09-10 11:05:29 -07001731 return getExecutablePrerequisite("compiler");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001732 }
1733
1734 /**
1735 * Returns the (unmodifiable, ordered) list of artifacts which are the outputs
1736 * of this target.
1737 *
1738 * <p>Each element in this list is associated with a single output, either
1739 * declared implicitly (via setImplicitOutputsFunction()) or explicitly
1740 * (listed in the 'outs' attribute of our rule).
1741 */
1742 public final ImmutableList<Artifact> getOutputArtifacts() {
1743 ImmutableList.Builder<Artifact> artifacts = ImmutableList.builder();
1744 for (OutputFile out : getRule().getOutputFiles()) {
1745 artifacts.add(createOutputArtifact(out));
1746 }
1747 return artifacts.build();
1748 }
1749
1750 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001751 * Like {@link #getOutputArtifacts()} but for a singular output item.
1752 * Reports an error if the "out" attribute is not a singleton.
1753 *
1754 * @return null if the output list is empty, the artifact for the first item
1755 * of the output list otherwise
1756 */
1757 public Artifact getOutputArtifact() {
1758 List<Artifact> outs = getOutputArtifacts();
1759 if (outs.size() != 1) {
1760 attributeError("out", "exactly one output file required");
1761 if (outs.isEmpty()) {
1762 return null;
1763 }
1764 }
1765 return outs.get(0);
1766 }
1767
plf727a07d2019-02-01 02:27:35 -08001768 @Override
janakr658d47f2019-05-29 11:11:30 -07001769 public final Artifact.DerivedArtifact getRelatedArtifact(
1770 PathFragment pathFragment, String extension) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001771 PathFragment file = FileSystemUtils.replaceExtension(pathFragment, extension);
Googler0617f2c2020-10-22 08:43:54 -07001772 return getDerivedArtifact(file, getConfiguration().getBinDirectory(getLabel().getRepository()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001773 }
1774
1775 /**
Googlerf812a2f2016-06-13 16:14:10 +00001776 * Returns true if the target for this context is a test target.
1777 */
1778 public boolean isTestTarget() {
1779 return TargetUtils.isTestRule(getTarget());
1780 }
1781
Googlercfdeb4d2018-02-08 07:13:33 -08001782 /** Returns true if the testonly attribute is set on this context. */
1783 public boolean isTestOnlyTarget() {
1784 return attributes().has("testonly", Type.BOOLEAN) && attributes().get("testonly", Type.BOOLEAN);
1785 }
1786
Googlerf812a2f2016-06-13 16:14:10 +00001787 /**
Klaus Aehliga85af942019-10-29 07:48:32 -07001788 * Returns true if {@code label} is visible from {@code prerequisite}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001789 *
1790 * <p>This only computes the logic as implemented by the visibility system. The final decision
jcater0de10972020-04-07 12:15:05 -07001791 * whether a dependency is allowed is made by {@link PrerequisiteValidator}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001792 */
Klaus Aehliga85af942019-10-29 07:48:32 -07001793 public static boolean isVisible(Label label, TransitiveInfoCollection prerequisite) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001794 // Check visibility attribute
cushon34ff85e2017-11-15 08:59:27 -08001795 for (PackageGroupContents specification :
Ulf Adamscd31d3b2019-12-16 00:50:03 -08001796 prerequisite.getProvider(VisibilityProvider.class).getVisibility().toList()) {
Klaus Aehliga85af942019-10-29 07:48:32 -07001797 if (specification.containsPackage(label.getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001798 return true;
1799 }
1800 }
1801
1802 return false;
1803 }
1804
1805 /**
Klaus Aehliga85af942019-10-29 07:48:32 -07001806 * Returns true if {@code rule} is visible from {@code prerequisite}.
1807 *
1808 * <p>This only computes the logic as implemented by the visibility system. The final decision
jcater0de10972020-04-07 12:15:05 -07001809 * whether a dependency is allowed is made by {@link PrerequisiteValidator}.
Klaus Aehliga85af942019-10-29 07:48:32 -07001810 */
1811 public static boolean isVisible(Rule rule, TransitiveInfoCollection prerequisite) {
1812 return isVisible(rule.getLabel(), prerequisite);
1813 }
1814
dchai40f464c2019-11-29 02:23:06 -08001815 /** @return the set of features applicable for the current rule. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001816 public ImmutableSet<String> getFeatures() {
Googler993f1de2018-02-20 02:31:10 -08001817 return enabledFeatures;
1818 }
1819
dchai40f464c2019-11-29 02:23:06 -08001820 /** @return the set of features that are disabled for the current rule. */
Googler993f1de2018-02-20 02:31:10 -08001821 public ImmutableSet<String> getDisabledFeatures() {
1822 return disabledFeatures;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001823 }
1824
Florian Weikertb8a6a942015-09-25 12:36:08 +00001825 @Override
plf43109892019-02-12 05:45:05 -08001826 public RuleErrorConsumer getRuleErrorConsumer() {
1827 return this;
1828 }
1829
jhorvitz7410c802020-07-22 11:55:07 -07001830 /**
1831 * Returns {@code true} if a {@link RequiredConfigFragmentsProvider} should be included for this
1832 * rule.
1833 */
1834 public boolean shouldIncludeRequiredConfigFragmentsProvider() {
1835 IncludeConfigFragmentsEnum setting =
1836 getConfiguration()
1837 .getOptions()
1838 .get(CoreOptions.class)
1839 .includeRequiredConfigFragmentsProvider;
1840 switch (setting) {
1841 case OFF:
1842 return false;
1843 case DIRECT_HOST_ONLY:
1844 return getConfiguration().isHostConfiguration();
1845 case DIRECT:
1846 case TRANSITIVE:
1847 return true;
1848 }
1849 throw new IllegalStateException("Unknown setting: " + setting);
1850 }
1851
plf43109892019-02-12 05:45:05 -08001852 @Override
Florian Weikertb8a6a942015-09-25 12:36:08 +00001853 public String toString() {
1854 return "RuleContext(" + getLabel() + ", " + getConfiguration() + ")";
1855 }
1856
brandjonbfd332e2020-12-17 14:56:04 -08001857 /** Builder class for a RuleContext. */
1858 // TODO(bazel-team): I get the feeling we could delete much of the boilerplate by replacing some
1859 // of these fields with a RuleClassProvider -- both in the builder and in the RuleContext itself.
1860 public static final class Builder implements RuleErrorConsumer {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001861 private final AnalysisEnvironment env;
lpino5fe7ed02018-07-18 05:55:23 -07001862 private final Target target;
Michael Staibb51251e2015-09-29 23:31:51 +00001863 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
jhorvitz6380c2892021-05-03 10:13:52 -07001864 private FragmentClassSet universalFragments;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001865 private final BuildConfiguration configuration;
Greg Estren9eb1cf02015-06-26 22:18:35 +00001866 private final BuildConfiguration hostConfiguration;
jhorvitz3daedc32020-07-22 18:33:55 -07001867 private final ActionLookupKey actionOwnerSymbol;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001868 private final PrerequisiteValidator prerequisiteValidator;
cparsonse8d450c2018-10-04 16:01:53 -07001869 private final RuleErrorConsumer reporter;
janakr9c101402018-03-10 06:48:59 -08001870 private OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap;
gregce79989f92021-02-01 07:01:55 -08001871 private ConfigConditions configConditions;
brandjonbfd332e2020-12-17 14:56:04 -08001872 private String toolsRepository;
1873 private StarlarkSemantics starlarkSemantics;
1874 private Mutability mutability;
cushon34ff85e2017-11-15 08:59:27 -08001875 private NestedSet<PackageGroupContents> visibility;
Dmitry Lomovace678e2015-12-16 15:10:20 +00001876 private ImmutableMap<String, Attribute> aspectAttributes;
dslomov44d15712017-12-20 05:42:28 -08001877 private ImmutableList<Aspect> aspects;
juliexxiab5f9d742020-04-09 13:07:13 -07001878 private ToolchainCollection<ResolvedToolchainContext> toolchainContexts;
juliexxia3eb806e2020-07-15 08:42:34 -07001879 private ImmutableMap<String, String> rawExecProperties;
jcater802551e2020-04-15 09:59:58 -07001880 private ConstraintSemantics<RuleContext> constraintSemantics;
gregce966dc232019-10-18 15:34:07 -07001881 private ImmutableSet<String> requiredConfigFragments = ImmutableSet.of();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001882
ulfjack865b6212018-06-14 03:41:55 -07001883 @VisibleForTesting
1884 public Builder(
Michael Staib8824d5e2016-01-20 21:37:05 +00001885 AnalysisEnvironment env,
lpino5fe7ed02018-07-18 05:55:23 -07001886 Target target,
dslomov44d15712017-12-20 05:42:28 -08001887 ImmutableList<Aspect> aspects,
Michael Staib8824d5e2016-01-20 21:37:05 +00001888 BuildConfiguration configuration,
Greg Estren9eb1cf02015-06-26 22:18:35 +00001889 BuildConfiguration hostConfiguration,
Michael Staib8824d5e2016-01-20 21:37:05 +00001890 PrerequisiteValidator prerequisiteValidator,
janakreaff19c2019-01-31 13:59:40 -08001891 ConfigurationFragmentPolicy configurationFragmentPolicy,
jhorvitz3daedc32020-07-22 18:33:55 -07001892 ActionLookupKey actionOwnerSymbol) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001893 this.env = Preconditions.checkNotNull(env);
lpino5fe7ed02018-07-18 05:55:23 -07001894 this.target = Preconditions.checkNotNull(target);
dslomov44d15712017-12-20 05:42:28 -08001895 this.aspects = aspects;
Michael Staib8824d5e2016-01-20 21:37:05 +00001896 this.configurationFragmentPolicy = Preconditions.checkNotNull(configurationFragmentPolicy);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001897 this.configuration = Preconditions.checkNotNull(configuration);
Greg Estren9eb1cf02015-06-26 22:18:35 +00001898 this.hostConfiguration = Preconditions.checkNotNull(hostConfiguration);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001899 this.prerequisiteValidator = prerequisiteValidator;
janakreaff19c2019-01-31 13:59:40 -08001900 this.actionOwnerSymbol = Preconditions.checkNotNull(actionOwnerSymbol);
cparsonse8d450c2018-10-04 16:01:53 -07001901 if (configuration.allowAnalysisFailures()) {
1902 reporter = new SuppressingErrorReporter();
1903 } else {
ulfjack07917642019-09-12 02:09:36 -07001904 reporter =
1905 new ErrorReporter(
1906 env, target.getAssociatedRule(), configuration, getRuleClassNameForLogging());
cparsonse8d450c2018-10-04 16:01:53 -07001907 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001908 }
1909
ulfjack865b6212018-06-14 03:41:55 -07001910 @VisibleForTesting
juliexxia6fe70c22020-05-18 14:38:42 -07001911 public RuleContext build() throws InvalidExecGroupException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001912 Preconditions.checkNotNull(prerequisiteMap);
1913 Preconditions.checkNotNull(configConditions);
brandjonbfd332e2020-12-17 14:56:04 -08001914 Preconditions.checkNotNull(toolsRepository);
1915 Preconditions.checkNotNull(starlarkSemantics);
1916 Preconditions.checkNotNull(mutability);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001917 Preconditions.checkNotNull(visibility);
gregce6acfe4e2018-05-25 08:38:39 -07001918 Preconditions.checkNotNull(constraintSemantics);
lpino5fe7ed02018-07-18 05:55:23 -07001919 AttributeMap attributes =
gregce3d33d7b2021-04-20 10:35:03 -07001920 ConfiguredAttributeMapper.of(
1921 target.getAssociatedRule(), configConditions.asProviders(), configuration.checksum());
adonovanec1cdc92020-08-07 08:15:51 -07001922 checkAttributesNonEmpty(attributes);
janakr9c101402018-03-10 06:48:59 -08001923 ListMultimap<String, ConfiguredTargetAndData> targetMap = createTargetMap();
gregce79989f92021-02-01 07:01:55 -08001924 // This conditionally checks visibility on config_setting rules based on
1925 // --config_setting_visibility_policy. This should be removed as soon as it's deemed safe
1926 // to unconditionally check visibility. See https://github.com/bazelbuild/bazel/issues/12669.
1927 if (target.getPackage().getConfigSettingVisibilityPolicy()
1928 != ConfigSettingVisibilityPolicy.LEGACY_OFF) {
1929 Attribute configSettingAttr = attributes.getAttributeDefinition("$config_dependencies");
1930 for (ConfiguredTargetAndData condition : configConditions.asConfiguredTargets().values()) {
1931 validateDirectPrerequisite(configSettingAttr, condition);
1932 }
1933 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001934 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap =
gregce79989f92021-02-01 07:01:55 -08001935 createFilesetEntryMap(target.getAssociatedRule(), configConditions.asProviders());
juliexxia3eb806e2020-07-15 08:42:34 -07001936 if (rawExecProperties == null) {
1937 if (!attributes.has(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT)) {
1938 rawExecProperties = ImmutableMap.of();
1939 } else {
1940 rawExecProperties =
1941 ImmutableMap.copyOf(attributes.get(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT));
1942 }
1943 }
Michael Staib8824d5e2016-01-20 21:37:05 +00001944 return new RuleContext(
1945 this,
Nathan Harmatafcb17112016-04-13 16:56:58 +00001946 attributes,
Michael Staib8824d5e2016-01-20 21:37:05 +00001947 targetMap,
1948 filesetEntryMap,
gregce79989f92021-02-01 07:01:55 -08001949 configConditions.asProviders(),
lberki78651d42018-04-06 01:52:58 -07001950 universalFragments,
Michael Staib8824d5e2016-01-20 21:37:05 +00001951 getRuleClassNameForLogging(),
janakreaff19c2019-01-31 13:59:40 -08001952 actionOwnerSymbol,
jhorvitz6380c2892021-05-03 10:13:52 -07001953 firstNonNull(aspectAttributes, ImmutableMap.of()),
juliexxiab5f9d742020-04-09 13:07:13 -07001954 toolchainContexts,
gregce966dc232019-10-18 15:34:07 -07001955 constraintSemantics,
brandjonbfd332e2020-12-17 14:56:04 -08001956 requiredConfigFragments,
1957 toolsRepository,
1958 starlarkSemantics,
1959 mutability);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001960 }
1961
adonovanec1cdc92020-08-07 08:15:51 -07001962 private void checkAttributesNonEmpty(AttributeMap attributes) {
1963 for (String attributeName : attributes.getAttributeNames()) {
1964 Attribute attr = attributes.getAttributeDefinition(attributeName);
1965 if (!attr.isNonEmpty()) {
1966 continue;
1967 }
1968 Object attributeValue = attributes.get(attributeName, attr.getType());
1969
1970 // TODO(adonovan): define in terms of Starlark.len?
1971 boolean isEmpty = false;
1972 if (attributeValue instanceof List<?>) {
1973 isEmpty = ((List) attributeValue).isEmpty();
1974 } else if (attributeValue instanceof Map<?, ?>) {
1975 isEmpty = ((Map) attributeValue).isEmpty();
1976 }
1977 if (isEmpty) {
1978 reporter.attributeError(attr.getName(), "attribute must be non empty");
1979 }
1980 }
Nathan Harmatafcb17112016-04-13 16:56:58 +00001981 }
1982
brandjonbfd332e2020-12-17 14:56:04 -08001983 // TODO(bazel-team): This field is only used by BazelStarlarkContext. Investigate whether that's
1984 // even needed in the analysis phase, and delete it if not.
1985 public Builder setToolsRepository(String toolsRepository) {
1986 this.toolsRepository = toolsRepository;
1987 return this;
1988 }
1989
1990 public Builder setStarlarkSemantics(StarlarkSemantics starlarkSemantics) {
1991 this.starlarkSemantics = starlarkSemantics;
1992 return this;
1993 }
1994
1995 public Builder setMutability(Mutability mutability) {
1996 this.mutability = mutability;
1997 return this;
1998 }
1999
ulfjack865b6212018-06-14 03:41:55 -07002000 public Builder setVisibility(NestedSet<PackageGroupContents> visibility) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002001 this.visibility = visibility;
2002 return this;
2003 }
2004
2005 /**
2006 * Sets the prerequisites and checks their visibility. It also generates appropriate error or
2007 * warning messages and sets the error flag as appropriate.
2008 */
ulfjack865b6212018-06-14 03:41:55 -07002009 public Builder setPrerequisites(
janakr9c101402018-03-10 06:48:59 -08002010 OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002011 this.prerequisiteMap = Preconditions.checkNotNull(prerequisiteMap);
2012 return this;
2013 }
2014
2015 /**
Carmi Grushko06f65f72015-11-02 22:42:24 +00002016 * Adds attributes which are defined by an Aspect (and not by RuleClass).
2017 */
ulfjack865b6212018-06-14 03:41:55 -07002018 public Builder setAspectAttributes(Map<String, Attribute> aspectAttributes) {
Dmitry Lomovace678e2015-12-16 15:10:20 +00002019 this.aspectAttributes = ImmutableMap.copyOf(aspectAttributes);
Carmi Grushko06f65f72015-11-02 22:42:24 +00002020 return this;
2021 }
2022
2023 /**
gregce79989f92021-02-01 07:01:55 -08002024 * Sets the configuration conditions needed to determine which paths to follow for this rule's
2025 * configurable attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002026 */
gregce79989f92021-02-01 07:01:55 -08002027 public Builder setConfigConditions(ConfigConditions configConditions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002028 this.configConditions = Preconditions.checkNotNull(configConditions);
2029 return this;
2030 }
2031
jcatera666f002020-04-14 14:55:20 -07002032 /** Sets the fragment that can be legally accessed even when not explicitly declared. */
jhorvitz6380c2892021-05-03 10:13:52 -07002033 public Builder setUniversalFragments(FragmentClassSet fragments) {
Greg Estrenc5a352f2015-11-13 17:25:36 +00002034 // TODO(bazel-team): Add this directly to ConfigurationFragmentPolicy, so we
2035 // don't need separate logic specifically for checking this fragment. The challenge is
2036 // that we need RuleClassProvider to figure out what this fragment is, and not every
2037 // call state that creates ConfigurationFragmentPolicy has access to that.
lberki78651d42018-04-06 01:52:58 -07002038 this.universalFragments = fragments;
Greg Estrenc5a352f2015-11-13 17:25:36 +00002039 return this;
2040 }
2041
John Catercdfa9ca2019-04-05 12:32:09 -07002042 /** Sets the {@link ResolvedToolchainContext} used to access toolchains used by this rule. */
2043 public Builder setToolchainContext(ResolvedToolchainContext toolchainContext) {
juliexxiab5f9d742020-04-09 13:07:13 -07002044 Preconditions.checkState(
2045 this.toolchainContexts == null,
2046 "toolchainContexts has already been set for this Builder");
2047 this.toolchainContexts =
jcater50375372020-06-02 08:51:33 -07002048 ToolchainCollection.<ResolvedToolchainContext>builder()
juliexxiab5f9d742020-04-09 13:07:13 -07002049 .addDefaultContext(toolchainContext)
2050 .build();
2051 return this;
2052 }
2053
2054 /** Sets the collection of {@link ResolvedToolchainContext}s available to this rule. */
2055 @VisibleForTesting
2056 public Builder setToolchainContexts(
2057 ToolchainCollection<ResolvedToolchainContext> toolchainContexts) {
2058 Preconditions.checkState(
2059 this.toolchainContexts == null,
2060 "toolchainContexts has already been set for this Builder");
2061 this.toolchainContexts = toolchainContexts;
John Cater13263f72017-05-24 19:06:47 +02002062 return this;
2063 }
2064
juliexxia3eb806e2020-07-15 08:42:34 -07002065 /**
2066 * Warning: if you set the exec properties using this method any exec_properties attribute value
2067 * will be ignored in favor of this value.
2068 */
2069 public Builder setExecProperties(ImmutableMap<String, String> execProperties) {
2070 this.rawExecProperties = execProperties;
2071 return this;
2072 }
2073
jcater802551e2020-04-15 09:59:58 -07002074 public Builder setConstraintSemantics(ConstraintSemantics<RuleContext> constraintSemantics) {
gregce6acfe4e2018-05-25 08:38:39 -07002075 this.constraintSemantics = constraintSemantics;
2076 return this;
2077 }
2078
gregce966dc232019-10-18 15:34:07 -07002079 public Builder setRequiredConfigFragments(ImmutableSet<String> requiredConfigFragments) {
2080 this.requiredConfigFragments = requiredConfigFragments;
2081 return this;
2082 }
2083
janakr9c101402018-03-10 06:48:59 -08002084 private boolean validateFilesetEntry(FilesetEntry filesetEntry, ConfiguredTargetAndData src) {
felly2b3befd2018-08-10 10:37:56 -07002085 NestedSet<Artifact> filesToBuild =
2086 src.getConfiguredTarget().getProvider(FileProvider.class).getFilesToBuild();
ulfjack8d8f62f2019-12-05 15:03:53 -08002087 if (filesToBuild.isSingleton() && filesToBuild.getSingleton().isFileset()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002088 return true;
2089 }
felly2b3befd2018-08-10 10:37:56 -07002090
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002091 if (filesetEntry.isSourceFileset()) {
2092 return true;
2093 }
2094
2095 Target srcTarget = src.getTarget();
2096 if (!(srcTarget instanceof FileTarget)) {
2097 attributeError("entries", String.format(
2098 "Invalid 'srcdir' target '%s'. Must be another Fileset or package",
2099 srcTarget.getLabel()));
2100 return false;
2101 }
2102
2103 if (srcTarget instanceof OutputFile) {
2104 attributeWarning("entries", String.format("'srcdir' target '%s' is not an input file. "
2105 + "This forces the Fileset to be executed unconditionally",
2106 srcTarget.getLabel()));
2107 }
2108
2109 return true;
2110 }
2111
2112 /**
2113 * Determines and returns a map from attribute name to list of configured fileset entries, based
2114 * on a PrerequisiteMap instance.
2115 */
2116 private ListMultimap<String, ConfiguredFilesetEntry> createFilesetEntryMap(
Lukacs Berki7894c182016-05-10 12:07:01 +00002117 final Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
lpino5fe7ed02018-07-18 05:55:23 -07002118 if (!target.getTargetKind().equals("Fileset rule")) {
2119 return ImmutableSortedKeyListMultimap.<String, ConfiguredFilesetEntry>builder().build();
2120 }
2121
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002122 final ImmutableSortedKeyListMultimap.Builder<String, ConfiguredFilesetEntry> mapBuilder =
2123 ImmutableSortedKeyListMultimap.builder();
2124 for (Attribute attr : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00002125 if (attr.getType() != BuildType.FILESET_ENTRY_LIST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002126 continue;
2127 }
2128 String attributeName = attr.getName();
janakr9c101402018-03-10 06:48:59 -08002129 Map<Label, ConfiguredTargetAndData> ctMap = new HashMap<>();
2130 for (ConfiguredTargetAndData prerequisite : prerequisiteMap.get(attr)) {
janakrf3e6f252018-01-18 07:45:12 -08002131 ctMap.put(
2132 AliasProvider.getDependencyLabel(prerequisite.getConfiguredTarget()), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002133 }
gregce3d33d7b2021-04-20 10:35:03 -07002134 List<FilesetEntry> entries =
2135 ConfiguredAttributeMapper.of(rule, configConditions, configuration.checksum())
2136 .get(attributeName, BuildType.FILESET_ENTRY_LIST);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002137 for (FilesetEntry entry : entries) {
2138 if (entry.getFiles() == null) {
2139 Label label = entry.getSrcLabel();
janakr9c101402018-03-10 06:48:59 -08002140 ConfiguredTargetAndData src = ctMap.get(label);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002141 if (!validateFilesetEntry(entry, src)) {
2142 continue;
2143 }
2144
janakrf3e6f252018-01-18 07:45:12 -08002145 mapBuilder.put(
2146 attributeName, new ConfiguredFilesetEntry(entry, src.getConfiguredTarget()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002147 } else {
2148 ImmutableList.Builder<TransitiveInfoCollection> files = ImmutableList.builder();
2149 for (Label file : entry.getFiles()) {
janakrf3e6f252018-01-18 07:45:12 -08002150 files.add(ctMap.get(file).getConfiguredTarget());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002151 }
2152 mapBuilder.put(attributeName, new ConfiguredFilesetEntry(entry, files.build()));
2153 }
2154 }
2155 }
2156 return mapBuilder.build();
2157 }
2158
janakrf3e6f252018-01-18 07:45:12 -08002159 /** Determines and returns a map from attribute name to list of configured targets. */
janakr9c101402018-03-10 06:48:59 -08002160 private ImmutableSortedKeyListMultimap<String, ConfiguredTargetAndData> createTargetMap() {
2161 ImmutableSortedKeyListMultimap.Builder<String, ConfiguredTargetAndData> mapBuilder =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002162 ImmutableSortedKeyListMultimap.builder();
2163
janakr9c101402018-03-10 06:48:59 -08002164 for (Map.Entry<Attribute, Collection<ConfiguredTargetAndData>> entry :
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002165 prerequisiteMap.asMap().entrySet()) {
2166 Attribute attribute = entry.getKey();
2167 if (attribute == null) {
2168 continue;
2169 }
lberki1cd6d1e2017-06-14 16:20:19 +02002170
2171 if (attribute.isSingleArtifact() && entry.getValue().size() > 1) {
2172 attributeError(attribute.getName(), "must contain a single dependency");
2173 continue;
2174 }
2175
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002176 if (attribute.isSilentRuleClassFilter()) {
2177 Predicate<RuleClass> filter = attribute.getAllowedRuleClassesPredicate();
janakr9c101402018-03-10 06:48:59 -08002178 for (ConfiguredTargetAndData configuredTarget : entry.getValue()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002179 Target prerequisiteTarget = configuredTarget.getTarget();
2180 if ((prerequisiteTarget instanceof Rule)
2181 && filter.apply(((Rule) prerequisiteTarget).getRuleClassObject())) {
2182 validateDirectPrerequisite(attribute, configuredTarget);
2183 mapBuilder.put(attribute.getName(), configuredTarget);
2184 }
2185 }
2186 } else {
janakr9c101402018-03-10 06:48:59 -08002187 for (ConfiguredTargetAndData configuredTarget : entry.getValue()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002188 validateDirectPrerequisite(attribute, configuredTarget);
2189 mapBuilder.put(attribute.getName(), configuredTarget);
2190 }
2191 }
2192 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002193 return mapBuilder.build();
2194 }
2195
cparsons963881a2018-10-03 14:23:55 -07002196 /**
2197 * Post a raw event to the analysis environment's event handler. This circumvents normal
2198 * error and warning reporting functionality to post events, and should only be used
2199 * in rare cases where a custom event needs to be handled.
2200 */
Klaus Aehlig16a107d2017-05-31 18:02:43 +02002201 public void post(Postable event) {
cparsons963881a2018-10-03 14:23:55 -07002202 env.getEventHandler().post(event);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002203 }
2204
Florian Weikertb8a6a942015-09-25 12:36:08 +00002205 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002206 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002207 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002208 }
2209
Florian Weikertb8a6a942015-09-25 12:36:08 +00002210 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002211 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002212 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002213 }
2214
Florian Weikertb8a6a942015-09-25 12:36:08 +00002215 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002216 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002217 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002218 }
2219
Florian Weikertb8a6a942015-09-25 12:36:08 +00002220 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002221 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002222 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002223 }
2224
cparsons0dcffc52017-10-13 23:40:31 +02002225 @Override
cparsons0dcffc52017-10-13 23:40:31 +02002226 public boolean hasErrors() {
2227 return reporter.hasErrors();
2228 }
2229
janakrf3e6f252018-01-18 07:45:12 -08002230 private String badPrerequisiteMessage(
lberkiee2dcae2018-03-28 05:49:04 -07002231 ConfiguredTargetAndData prerequisite, String reason, boolean isWarning) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002232 String msgReason = reason != null ? " (" + reason + ")" : "";
2233 if (isWarning) {
Googlere49cd592016-07-29 19:32:38 +00002234 return String.format(
lberkiee2dcae2018-03-28 05:49:04 -07002235 "%s is unexpected here%s; continuing anyway",
2236 AliasProvider.describeTargetWithAliases(prerequisite, TargetMode.WITH_KIND),
Googlere49cd592016-07-29 19:32:38 +00002237 msgReason);
2238 }
lberkiee2dcae2018-03-28 05:49:04 -07002239 return String.format("%s is misplaced here%s",
2240 AliasProvider.describeTargetWithAliases(prerequisite, TargetMode.WITH_KIND), msgReason);
Googlere49cd592016-07-29 19:32:38 +00002241 }
2242
janakrf3e6f252018-01-18 07:45:12 -08002243 private void reportBadPrerequisite(
2244 Attribute attribute,
janakr9c101402018-03-10 06:48:59 -08002245 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08002246 String reason,
2247 boolean isWarning) {
lberkiee2dcae2018-03-28 05:49:04 -07002248 String message = badPrerequisiteMessage(prerequisite, reason, isWarning);
Googlere49cd592016-07-29 19:32:38 +00002249 if (isWarning) {
2250 attributeWarning(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002251 } else {
Googlere49cd592016-07-29 19:32:38 +00002252 attributeError(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002253 }
2254 }
2255
janakrf3e6f252018-01-18 07:45:12 -08002256 private void validateDirectPrerequisiteType(
janakr9c101402018-03-10 06:48:59 -08002257 ConfiguredTargetAndData prerequisite, Attribute attribute) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002258 Target prerequisiteTarget = prerequisite.getTarget();
2259 Label prerequisiteLabel = prerequisiteTarget.getLabel();
2260
2261 if (prerequisiteTarget instanceof Rule) {
2262 Rule prerequisiteRule = (Rule) prerequisiteTarget;
2263
lpino5fe7ed02018-07-18 05:55:23 -07002264 String reason =
2265 attribute
2266 .getValidityPredicate()
2267 .checkValid(target.getAssociatedRule(), prerequisiteRule);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002268 if (reason != null) {
lberkiee2dcae2018-03-28 05:49:04 -07002269 reportBadPrerequisite(attribute, prerequisite, reason, false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002270 }
2271 }
2272
Yun Pengefd7ca12016-03-03 13:14:38 +00002273 if (prerequisiteTarget instanceof Rule) {
2274 validateRuleDependency(prerequisite, attribute);
2275 } else if (prerequisiteTarget instanceof FileTarget) {
2276 if (attribute.isStrictLabelCheckingEnabled()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002277 if (!attribute.getAllowedFileTypesPredicate()
2278 .apply(((FileTarget) prerequisiteTarget).getFilename())) {
2279 if (prerequisiteTarget instanceof InputFile
2280 && !((InputFile) prerequisiteTarget).getPath().exists()) {
2281 // Misplaced labels, no corresponding target exists
2282 if (attribute.getAllowedFileTypesPredicate().isNone()
2283 && !((InputFile) prerequisiteTarget).getFilename().contains(".")) {
2284 // There are no allowed files in the attribute but it's not a valid rule,
2285 // and the filename doesn't contain a dot --> probably a misspelled rule
2286 attributeError(attribute.getName(),
2287 "rule '" + prerequisiteLabel + "' does not exist");
2288 } else {
2289 attributeError(attribute.getName(),
2290 "target '" + prerequisiteLabel + "' does not exist");
2291 }
2292 } else {
2293 // The file exists but has a bad extension
lberkiee2dcae2018-03-28 05:49:04 -07002294 reportBadPrerequisite(attribute, prerequisite,
Ulf Adams07dba942015-03-05 14:47:37 +00002295 "expected " + attribute.getAllowedFileTypesPredicate(), false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002296 }
2297 }
2298 }
2299 }
2300 }
2301
Michael Staib2707a882016-09-16 21:06:40 +00002302 /** Returns whether the context being constructed is for the evaluation of an aspect. */
2303 public boolean forAspect() {
dslomov44d15712017-12-20 05:42:28 -08002304 return !aspects.isEmpty();
Michael Staib2707a882016-09-16 21:06:40 +00002305 }
2306
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002307 public Rule getRule() {
lpino5fe7ed02018-07-18 05:55:23 -07002308 return target.getAssociatedRule();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002309 }
2310
Michael Staib8824d5e2016-01-20 21:37:05 +00002311 /**
Klaus Aehlig38053002019-10-29 09:54:32 -07002312 * Expose the Starlark semantics that governs the building of this rule (and the rest of the
2313 * build)
2314 */
2315 public StarlarkSemantics getStarlarkSemantics() throws InterruptedException {
gregce61ec8d12020-05-18 11:02:05 -07002316 return env.getStarlarkSemantics();
Klaus Aehlig38053002019-10-29 09:54:32 -07002317 }
2318
2319 /**
Michael Staib8824d5e2016-01-20 21:37:05 +00002320 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
2321 */
2322 public String getRuleClassNameForLogging() {
dslomov44d15712017-12-20 05:42:28 -08002323 if (aspects.isEmpty()) {
lpino5fe7ed02018-07-18 05:55:23 -07002324 return target.getAssociatedRule().getRuleClass();
Dmitry Lomov15756522016-12-16 16:52:37 +00002325 }
2326
dslomov44d15712017-12-20 05:42:28 -08002327 return Joiner.on(",")
2328 .join(aspects.stream().map(a -> a.getDescriptor()).collect(Collectors.toList()))
2329 + " aspect on "
lpino5fe7ed02018-07-18 05:55:23 -07002330 + target.getAssociatedRule().getRuleClass();
Michael Staib8824d5e2016-01-20 21:37:05 +00002331 }
2332
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002333 public BuildConfiguration getConfiguration() {
2334 return configuration;
2335 }
2336
2337 /**
2338 * @return true if {@code rule} is visible from {@code prerequisite}.
jcater0de10972020-04-07 12:15:05 -07002339 * <p>This only computes the logic as implemented by the visibility system. The final
2340 * decision whether a dependency is allowed is made by {@link PrerequisiteValidator}, who is
2341 * supposed to call this method to determine whether a dependency is allowed as per
2342 * visibility rules.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002343 */
2344 public boolean isVisible(TransitiveInfoCollection prerequisite) {
lpino5fe7ed02018-07-18 05:55:23 -07002345 return RuleContext.isVisible(target.getAssociatedRule(), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002346 }
2347
janakrf3e6f252018-01-18 07:45:12 -08002348 private void validateDirectPrerequisiteFileTypes(
janakr9c101402018-03-10 06:48:59 -08002349 ConfiguredTargetAndData prerequisite, Attribute attribute) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002350 if (attribute.isSkipAnalysisTimeFileTypeCheck()) {
2351 return;
2352 }
2353 FileTypeSet allowedFileTypes = attribute.getAllowedFileTypesPredicate();
Ulf Adams788fd1a2015-03-12 13:54:09 +00002354 if (allowedFileTypes == null) {
2355 // It's not a label or label_list attribute.
2356 return;
2357 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002358 if (allowedFileTypes == FileTypeSet.ANY_FILE && !attribute.isNonEmpty()
2359 && !attribute.isSingleArtifact()) {
2360 return;
2361 }
2362
2363 // If we allow any file we still need to check if there are actually files generated
2364 // Note that this check only runs for ANY_FILE predicates if the attribute is NON_EMPTY
2365 // or SINGLE_ARTIFACT
2366 // If we performed this check when allowedFileTypes == NO_FILE this would
2367 // always throw an error in those cases
2368 if (allowedFileTypes != FileTypeSet.NO_FILE) {
Ulf Adamscd31d3b2019-12-16 00:50:03 -08002369 NestedSet<Artifact> artifacts =
janakrf3e6f252018-01-18 07:45:12 -08002370 prerequisite.getConfiguredTarget().getProvider(FileProvider.class).getFilesToBuild();
Ulf Adamscd31d3b2019-12-16 00:50:03 -08002371 if (attribute.isSingleArtifact() && !artifacts.isSingleton()) {
janakrf3e6f252018-01-18 07:45:12 -08002372 attributeError(
2373 attribute.getName(),
2374 "'" + prerequisite.getTarget().getLabel() + "' must produce a single file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002375 return;
2376 }
Ulf Adamscd31d3b2019-12-16 00:50:03 -08002377 for (Artifact sourceArtifact : artifacts.toList()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002378 if (allowedFileTypes.apply(sourceArtifact.getFilename())) {
2379 return;
2380 }
Googler2d90b6a2018-07-26 12:37:34 -07002381 if (sourceArtifact.isTreeArtifact()) {
2382 return;
2383 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002384 }
janakrf3e6f252018-01-18 07:45:12 -08002385 attributeError(
2386 attribute.getName(),
2387 "'"
2388 + prerequisite.getTarget().getLabel()
2389 + "' does not produce any "
2390 + getRuleClassNameForLogging()
2391 + " "
2392 + attribute.getName()
2393 + " files (expected "
2394 + allowedFileTypes
2395 + ")");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002396 }
2397 }
2398
dslomov7df85152017-08-01 20:47:59 +02002399 /**
dslomovc13bb392017-08-02 23:29:54 +02002400 * Because some rules still have to use allowedRuleClasses to do rule dependency validation. A
2401 * dependency is valid if it is from a rule in allowedRuledClasses, OR if all of the providers
2402 * in requiredProviders are provided by the target.
dslomov7df85152017-08-01 20:47:59 +02002403 */
janakr9c101402018-03-10 06:48:59 -08002404 private void validateRuleDependency(ConfiguredTargetAndData prerequisite, Attribute attribute) {
dslomov7df85152017-08-01 20:47:59 +02002405
dslomovc13bb392017-08-02 23:29:54 +02002406 Set<String> unfulfilledRequirements = new LinkedHashSet<>();
2407 if (checkRuleDependencyClass(prerequisite, attribute, unfulfilledRequirements)) {
2408 return;
2409 }
2410
2411 if (checkRuleDependencyClassWarnings(prerequisite, attribute)) {
2412 return;
2413 }
2414
2415 if (checkRuleDependencyMandatoryProviders(prerequisite, attribute, unfulfilledRequirements)) {
2416 return;
2417 }
2418
2419 // not allowed rule class and some mandatory providers missing => reject.
2420 if (!unfulfilledRequirements.isEmpty()) {
2421 attributeError(
2422 attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
2423 }
2424 }
2425
2426 /** Check if prerequisite should be allowed based on its rule class. */
2427 private boolean checkRuleDependencyClass(
janakr9c101402018-03-10 06:48:59 -08002428 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08002429 Attribute attribute,
2430 Set<String> unfulfilledRequirements) {
dslomovc32e1b12017-07-31 19:23:52 +02002431 if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
dslomovc13bb392017-08-02 23:29:54 +02002432 if (attribute
2433 .getAllowedRuleClassesPredicate()
2434 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002435 // prerequisite has an allowed rule class => accept.
dslomovc13bb392017-08-02 23:29:54 +02002436 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002437 }
2438 // remember that the rule class that was not allowed;
2439 // but maybe prerequisite provides required providers? do not reject yet.
dslomovc13bb392017-08-02 23:29:54 +02002440 unfulfilledRequirements.add(
dslomovc32e1b12017-07-31 19:23:52 +02002441 badPrerequisiteMessage(
dslomovc32e1b12017-07-31 19:23:52 +02002442 prerequisite,
2443 "expected " + attribute.getAllowedRuleClassesPredicate(),
dslomovc13bb392017-08-02 23:29:54 +02002444 false));
dslomovc32e1b12017-07-31 19:23:52 +02002445 }
dslomovc13bb392017-08-02 23:29:54 +02002446 return false;
2447 }
dslomovc32e1b12017-07-31 19:23:52 +02002448
dslomovc13bb392017-08-02 23:29:54 +02002449 /**
2450 * Check if prerequisite should be allowed with warning based on its rule class.
2451 *
2452 * <p>If yes, also issues said warning.
2453 */
2454 private boolean checkRuleDependencyClassWarnings(
janakr9c101402018-03-10 06:48:59 -08002455 ConfiguredTargetAndData prerequisite, Attribute attribute) {
dslomovc13bb392017-08-02 23:29:54 +02002456 if (attribute
2457 .getAllowedRuleClassesWarningPredicate()
2458 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002459 Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate();
dslomovc13bb392017-08-02 23:29:54 +02002460 reportBadPrerequisite(
2461 attribute,
dslomovc13bb392017-08-02 23:29:54 +02002462 prerequisite,
dslomovc32e1b12017-07-31 19:23:52 +02002463 allowedRuleClasses == Predicates.<RuleClass>alwaysTrue()
dslomovde965ac2017-07-31 21:07:51 +02002464 ? null
2465 : "expected " + allowedRuleClasses,
dslomovc32e1b12017-07-31 19:23:52 +02002466 true);
2467 // prerequisite has a rule class allowed with a warning => accept, emitting a warning.
dslomovc13bb392017-08-02 23:29:54 +02002468 return true;
2469 }
2470 return false;
2471 }
2472
2473 /** Check if prerequisite should be allowed based on required providers on the attribute. */
2474 private boolean checkRuleDependencyMandatoryProviders(
janakr9c101402018-03-10 06:48:59 -08002475 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08002476 Attribute attribute,
2477 Set<String> unfulfilledRequirements) {
dslomovc13bb392017-08-02 23:29:54 +02002478 RequiredProviders requiredProviders = attribute.getRequiredProviders();
2479
2480 if (requiredProviders.acceptsAny()) {
2481 // If no required providers specified, we do not know if we should accept.
2482 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002483 }
2484
janakrf3e6f252018-01-18 07:45:12 -08002485 if (prerequisite.getConfiguredTarget().satisfies(requiredProviders)) {
dslomovc13bb392017-08-02 23:29:54 +02002486 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002487 }
2488
dslomovc13bb392017-08-02 23:29:54 +02002489 unfulfilledRequirements.add(
2490 String.format(
2491 "'%s' does not have mandatory providers: %s",
janakrf3e6f252018-01-18 07:45:12 -08002492 prerequisite.getTarget().getLabel(),
2493 prerequisite
2494 .getConfiguredTarget()
2495 .missingProviders(requiredProviders)
2496 .getDescription()));
dslomovc32e1b12017-07-31 19:23:52 +02002497
dslomovc13bb392017-08-02 23:29:54 +02002498 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002499 }
2500
janakrf3e6f252018-01-18 07:45:12 -08002501 private void validateDirectPrerequisite(
janakr9c101402018-03-10 06:48:59 -08002502 Attribute attribute, ConfiguredTargetAndData prerequisite) {
Philipp Schrader3e969ff2020-12-10 09:05:37 -08002503 if (RuleContextConstraintSemantics.checkForIncompatibility(prerequisite.getConfiguredTarget())
2504 .isIncompatible()) {
2505 // If the prerequisite is incompatible (e.g. has an incompatible provider), we pretend that
2506 // there is no further validation needed. Otherwise, it would be difficult to make the
2507 // incompatible target satisfy things like required providers and file extensions.
2508 return;
2509 }
2510
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002511 validateDirectPrerequisiteType(prerequisite, attribute);
2512 validateDirectPrerequisiteFileTypes(prerequisite, attribute);
Greg Estren875c7a72015-09-24 19:57:54 +00002513 if (attribute.performPrereqValidatorCheck()) {
Ulf Adams0b638972015-09-08 13:25:35 +00002514 prerequisiteValidator.validate(this, prerequisite, attribute);
2515 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002516 }
2517 }
2518
ruperts8986b6e2017-10-17 00:26:29 +02002519 /** Helper class for reporting errors and warnings. */
cparsons963881a2018-10-03 14:23:55 -07002520 private static final class ErrorReporter extends EventHandlingErrorReporter
ruperts8986b6e2017-10-17 00:26:29 +02002521 implements RuleErrorConsumer {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002522 private final Rule rule;
ulfjack07917642019-09-12 02:09:36 -07002523 private final BuildConfiguration configuration;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002524
ulfjack07917642019-09-12 02:09:36 -07002525 ErrorReporter(
2526 AnalysisEnvironment env,
2527 Rule rule,
2528 BuildConfiguration configuration,
2529 String ruleClassNameForLogging) {
asteinbb82db782018-05-18 08:21:39 -07002530 super(ruleClassNameForLogging, env);
Florian Weikertb8a6a942015-09-25 12:36:08 +00002531 this.rule = rule;
ulfjack07917642019-09-12 02:09:36 -07002532 this.configuration = configuration;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002533 }
2534
2535 @Override
Googler706d75b2019-09-18 10:09:07 -07002536 protected String getMacroMessageAppendix(String unusedAttrName) {
2537 // TODO(b/141234726): Historically this reported the location
2538 // of the rule attribute in the macro call (assuming no **kwargs),
2539 // but we no longer locations for individual attributes.
2540 // We should record the instantiation call stack in each rule
2541 // and report the position of its topmost frame here.
asteinbb82db782018-05-18 08:21:39 -07002542 return rule.wasCreatedByMacro()
2543 ? String.format(
2544 ". Since this rule was created by the macro '%s', the error might have been "
Googler706d75b2019-09-18 10:09:07 -07002545 + "caused by the macro implementation",
2546 getGeneratorFunction())
asteinbb82db782018-05-18 08:21:39 -07002547 : "";
Florian Weikertb8a6a942015-09-25 12:36:08 +00002548 }
2549
Florian Weikertb8a6a942015-09-25 12:36:08 +00002550 private String getGeneratorFunction() {
Googlera40c64a2020-08-11 16:39:39 -07002551 return (String) rule.getAttr("generator_function");
Florian Weikertb8a6a942015-09-25 12:36:08 +00002552 }
asteinbb82db782018-05-18 08:21:39 -07002553
2554 @Override
2555 protected Label getLabel() {
2556 return rule.getLabel();
2557 }
2558
2559 @Override
ulfjack07917642019-09-12 02:09:36 -07002560 protected BuildConfiguration getConfiguration() {
2561 return configuration;
2562 }
2563
2564 @Override
asteinbb82db782018-05-18 08:21:39 -07002565 protected Location getRuleLocation() {
2566 return rule.getLocation();
2567 }
cparsonse8d450c2018-10-04 16:01:53 -07002568 }
asteinbb82db782018-05-18 08:21:39 -07002569
cparsonse8d450c2018-10-04 16:01:53 -07002570 /**
2571 * Implementation of an error consumer which does not post any events, saves rule and attribute
2572 * errors for future consumption, and drops warnings.
2573 */
2574 public static final class SuppressingErrorReporter implements RuleErrorConsumer {
2575 private final List<String> errorMessages = Lists.newArrayList();
2576
2577 @Override
2578 public void ruleWarning(String message) {}
2579
2580 @Override
2581 public void ruleError(String message) {
2582 errorMessages.add(message);
2583 }
2584
2585 @Override
2586 public void attributeWarning(String attrName, String message) {}
2587
2588 @Override
2589 public void attributeError(String attrName, String message) {
2590 errorMessages.add(message);
2591 }
2592
2593 @Override
2594 public boolean hasErrors() {
2595 return !errorMessages.isEmpty();
2596 }
2597
2598 /**
2599 * Returns the error message strings reported to this error consumer.
2600 */
2601 public List<String> getErrorMessages() {
2602 return errorMessages;
2603 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002604 }
2605}