blob: 6fe5f87c546f2b94c0fe1b1c84660f5e3d512d2c [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.analysis;
16
Janak Ramakrishnan7857c792016-03-21 08:35:35 +000017import com.google.common.annotations.VisibleForTesting;
Yun Peng5c34e962016-02-22 15:13:19 +000018import com.google.common.base.Joiner;
Googler59480b92016-07-22 17:06:40 +000019import com.google.common.base.Optional;
tomlua155b532017-11-08 20:12:47 +010020import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010021import com.google.common.base.Predicate;
Yun Pengefd7ca12016-03-03 13:14:38 +000022import com.google.common.base.Predicates;
Florian Weikert082c0542015-08-06 10:24:29 +000023import com.google.common.collect.ImmutableCollection;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010024import com.google.common.collect.ImmutableList;
25import com.google.common.collect.ImmutableListMultimap;
26import com.google.common.collect.ImmutableMap;
27import com.google.common.collect.ImmutableSet;
Manuel Klimek6d9fb362015-04-30 12:50:55 +000028import com.google.common.collect.ImmutableSortedSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.common.collect.Iterables;
30import com.google.common.collect.ListMultimap;
janakrf3e6f252018-01-18 07:45:12 -080031import com.google.common.collect.Lists;
mjhalupkade47f212018-02-12 12:31:21 -080032import com.google.common.collect.Maps;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033import com.google.common.collect.Multimaps;
34import com.google.common.collect.Sets;
Rumou Duan33bab462016-04-25 17:55:12 +000035import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
plf1f341a62019-04-01 14:02:14 -070036import com.google.devtools.build.lib.actions.ActionKeyContext;
janakreaff19c2019-01-31 13:59:40 -080037import com.google.devtools.build.lib.actions.ActionLookupValue;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010038import com.google.devtools.build.lib.actions.ActionOwner;
39import com.google.devtools.build.lib.actions.ActionRegistry;
40import com.google.devtools.build.lib.actions.Artifact;
cpeyserac09f0a2018-02-05 09:33:15 -080041import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
tomlu1cdcdf92018-01-16 11:07:51 -080042import com.google.devtools.build.lib.actions.ArtifactRoot;
lberkiee2dcae2018-03-28 05:49:04 -070043import com.google.devtools.build.lib.analysis.AliasProvider.TargetMode;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010044import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
Ulf Adamsc272e0f2015-04-22 19:56:21 +000045import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
47import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
Greg Estren66cadd32016-08-05 21:07:02 +000048import com.google.devtools.build.lib.analysis.config.BuildOptions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
Florian Weikert3f8aac92015-09-07 12:06:02 +000050import com.google.devtools.build.lib.analysis.config.FragmentCollection;
gregcebe55e112018-01-30 11:04:53 -080051import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
gregce7fa23ea2018-01-18 12:46:04 -080052import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
gregce6bc35ed2017-12-22 11:51:39 -080053import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
John Cater5adcd3e2019-03-28 10:14:32 -070054import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
gregce593f7f92017-09-19 02:02:21 +020055import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
gregce6acfe4e2018-05-25 08:38:39 -070056import com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics;
jcater0a1e9eb2019-12-17 09:58:38 -080057import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
John Cater15c90b32017-12-18 08:34:40 -080058import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
ulfjack01bf32e2017-11-02 17:50:07 -040059import com.google.devtools.build.lib.analysis.stringtemplate.TemplateContext;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000060import com.google.devtools.build.lib.cmdline.Label;
dslomovfd62e762017-09-19 16:55:53 +020061import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010062import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap;
63import com.google.devtools.build.lib.collect.nestedset.NestedSet;
64import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
Klaus Aehlig16a107d2017-05-31 18:02:43 +020065import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
dslomov44d15712017-12-20 05:42:28 -080066import com.google.devtools.build.lib.packages.Aspect;
Dmitry Lomov15756522016-12-16 16:52:37 +000067import com.google.devtools.build.lib.packages.AspectDescriptor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010068import com.google.devtools.build.lib.packages.Attribute;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010069import com.google.devtools.build.lib.packages.AttributeMap;
John Cater2c0dece2019-04-02 09:18:18 -070070import com.google.devtools.build.lib.packages.AttributeTransitionData;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000071import com.google.devtools.build.lib.packages.BuildType;
cparsons2d67cf92018-05-24 14:02:09 -070072import com.google.devtools.build.lib.packages.BuiltinProvider;
Michael Staibb51251e2015-09-29 23:31:51 +000073import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy;
cparsons78927792017-10-11 00:14:19 +020074import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010075import com.google.devtools.build.lib.packages.FileTarget;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000076import com.google.devtools.build.lib.packages.FilesetEntry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010077import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
dslomovde965ac2017-07-31 21:07:51 +020078import com.google.devtools.build.lib.packages.Info;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.lib.packages.InputFile;
dslomovde965ac2017-07-31 21:07:51 +020080import com.google.devtools.build.lib.packages.NativeProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010081import com.google.devtools.build.lib.packages.OutputFile;
cushon34ff85e2017-11-15 08:59:27 -080082import com.google.devtools.build.lib.packages.PackageSpecification.PackageGroupContents;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010083import com.google.devtools.build.lib.packages.RawAttributeMapper;
dslomovc13bb392017-08-02 23:29:54 +020084import com.google.devtools.build.lib.packages.RequiredProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085import com.google.devtools.build.lib.packages.Rule;
86import com.google.devtools.build.lib.packages.RuleClass;
87import com.google.devtools.build.lib.packages.RuleErrorConsumer;
Googler995ef632019-09-04 12:25:41 -070088import com.google.devtools.build.lib.packages.SymbolGenerator;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010089import com.google.devtools.build.lib.packages.Target;
90import com.google.devtools.build.lib.packages.TargetUtils;
Googlerc5fcc862019-09-06 16:17:47 -070091import com.google.devtools.build.lib.packages.Type;
92import com.google.devtools.build.lib.packages.Type.LabelClass;
janakr9c101402018-03-10 06:48:59 -080093import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094import com.google.devtools.build.lib.syntax.EvalException;
adonovanf5262c52020-04-02 09:25:14 -070095import com.google.devtools.build.lib.syntax.Location;
Klaus Aehlig38053002019-10-29 09:54:32 -070096import com.google.devtools.build.lib.syntax.StarlarkSemantics;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010097import com.google.devtools.build.lib.util.FileTypeSet;
cparsons0623d3c2018-10-23 16:06:30 -070098import com.google.devtools.build.lib.util.OS;
Greg Estrend5353252016-08-11 22:13:31 +000099import com.google.devtools.build.lib.util.OrderedSetMultimap;
Googlere49cd592016-07-29 19:32:38 +0000100import com.google.devtools.build.lib.util.StringUtil;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100101import com.google.devtools.build.lib.vfs.FileSystemUtils;
102import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100103import java.util.Collection;
104import java.util.HashMap;
105import java.util.HashSet;
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +0000106import java.util.LinkedHashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100107import java.util.List;
108import java.util.Map;
109import java.util.Set;
dslomov44d15712017-12-20 05:42:28 -0800110import java.util.stream.Collectors;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100111import javax.annotation.Nullable;
112
113/**
Lukacs Berki2300cd62016-05-19 11:06:37 +0000114 * The totality of data available during the analysis of a rule.
Janak Ramakrishnan81c5bd82016-03-22 20:07:43 +0000115 *
jcater02ce2a62020-04-07 08:06:00 -0700116 * <p>These objects should not outlast the analysis phase. Do not pass them to {@link
117 * com.google.devtools.build.lib.actions.Action} objects or other persistent objects. There are
118 * internal tests to ensure that RuleContext objects are not persisted that check the name of this
119 * class, so update those tests if you change this class's name.
Lukacs Berki2300cd62016-05-19 11:06:37 +0000120 *
ulfjack26d0e492017-08-07 13:42:33 +0200121 * @see com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100122 */
123public final class RuleContext extends TargetContext
124 implements ActionConstructionContext, ActionRegistry, RuleErrorConsumer {
Carmi Grushko33aa3062016-11-11 02:45:29 +0000125
ishikhman94c24b32019-08-30 04:46:25 -0700126 public boolean isAllowTagsPropagation() throws InterruptedException {
127 return this.getAnalysisEnvironment().getSkylarkSemantics().experimentalAllowTagsPropagation();
128 }
129
jcater0de10972020-04-07 12:15:05 -0700130 /** Custom dependency validation logic. */
131 public interface PrerequisiteValidator {
132 /**
133 * Checks whether the rule in {@code contextBuilder} is allowed to depend on {@code
134 * prerequisite} through the attribute {@code attribute}.
135 *
136 * <p>Can be used for enforcing any organization-specific policies about the layout of the
137 * workspace.
138 */
139 void validate(
140 Builder contextBuilder, ConfiguredTargetAndData prerequisite, Attribute attribute);
141 }
142
143 /** The configured version of FilesetEntry. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100144 @Immutable
145 public static final class ConfiguredFilesetEntry {
146 private final FilesetEntry entry;
147 private final TransitiveInfoCollection src;
148 private final ImmutableList<TransitiveInfoCollection> files;
149
150 ConfiguredFilesetEntry(FilesetEntry entry, TransitiveInfoCollection src) {
151 this.entry = entry;
152 this.src = src;
153 this.files = null;
154 }
155
156 ConfiguredFilesetEntry(FilesetEntry entry, ImmutableList<TransitiveInfoCollection> files) {
157 this.entry = entry;
158 this.src = null;
159 this.files = files;
160 }
161
162 public FilesetEntry getEntry() {
163 return entry;
164 }
165
166 public TransitiveInfoCollection getSrc() {
167 return src;
168 }
169
170 /**
171 * Targets from FilesetEntry.files, or null if the user omitted it.
172 */
173 @Nullable
Ulf Adams10993fe2016-04-19 12:55:12 +0000174 public ImmutableList<TransitiveInfoCollection> getFiles() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100175 return files;
176 }
177 }
178
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000179 private static final String HOST_CONFIGURATION_PROGRESS_TAG = "for host";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100180
181 private final Rule rule;
dslomov44d15712017-12-20 05:42:28 -0800182 /**
183 * A list of all aspects applied to the target. If this <code>RuleContext</code>
184 * is for a rule implementation, <code>aspects</code> is an empty list.
185 *
186 * Otherwise, the last aspect in <code>aspects</code> list is the aspect which
187 * this <code>RuleCointext</code> is for.
188 */
189 private final ImmutableList<Aspect> aspects;
Dmitry Lomov15756522016-12-16 16:52:37 +0000190 private final ImmutableList<AspectDescriptor> aspectDescriptors;
janakr9c101402018-03-10 06:48:59 -0800191 private final ListMultimap<String, ConfiguredTargetAndData> targetMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100192 private final ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap;
Lukacs Berki7894c182016-05-10 12:07:01 +0000193 private final ImmutableMap<Label, ConfigMatchingProvider> configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000194 private final AspectAwareAttributeMapper attributes;
Googler993f1de2018-02-20 02:31:10 -0800195 private final ImmutableSet<String> enabledFeatures;
196 private final ImmutableSet<String> disabledFeatures;
Michael Staib8824d5e2016-01-20 21:37:05 +0000197 private final String ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000198 private final BuildConfiguration hostConfiguration;
Michael Staibb51251e2015-09-29 23:31:51 +0000199 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
lberki78651d42018-04-06 01:52:58 -0700200 private final ImmutableList<Class<? extends BuildConfiguration.Fragment>> universalFragments;
cparsonse8d450c2018-10-04 16:01:53 -0700201 private final RuleErrorConsumer reporter;
juliexxiab5f9d742020-04-09 13:07:13 -0700202 @Nullable private final ToolchainCollection<ResolvedToolchainContext> toolchainContexts;
gregce6acfe4e2018-05-25 08:38:39 -0700203 private final ConstraintSemantics constraintSemantics;
gregce966dc232019-10-18 15:34:07 -0700204 private final ImmutableSet<String> requiredConfigFragments;
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000205
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100206 private ActionOwner actionOwner;
janakreaff19c2019-01-31 13:59:40 -0800207 private final SymbolGenerator<ActionLookupValue.ActionLookupKey> actionOwnerSymbolGenerator;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100208
209 /* lazily computed cache for Make variables, computed from the above. See get... method */
210 private transient ConfigurationMakeVariableContext configurationMakeVariableContext = null;
211
Dmitry Lomovace678e2015-12-16 15:10:20 +0000212 private RuleContext(
213 Builder builder,
Nathan Harmatafcb17112016-04-13 16:56:58 +0000214 AttributeMap attributes,
janakr9c101402018-03-10 06:48:59 -0800215 ListMultimap<String, ConfiguredTargetAndData> targetMap,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100216 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap,
Lukacs Berki7894c182016-05-10 12:07:01 +0000217 ImmutableMap<Label, ConfigMatchingProvider> configConditions,
janakreaff19c2019-01-31 13:59:40 -0800218 ImmutableList<Class<? extends Fragment>> universalFragments,
Michael Staib8824d5e2016-01-20 21:37:05 +0000219 String ruleClassNameForLogging,
janakreaff19c2019-01-31 13:59:40 -0800220 ActionLookupValue.ActionLookupKey actionLookupKey,
John Cater13263f72017-05-24 19:06:47 +0200221 ImmutableMap<String, Attribute> aspectAttributes,
juliexxiab5f9d742020-04-09 13:07:13 -0700222 @Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts,
gregce966dc232019-10-18 15:34:07 -0700223 ConstraintSemantics constraintSemantics,
224 ImmutableSet<String> requiredConfigFragments) {
lpino5fe7ed02018-07-18 05:55:23 -0700225 super(
226 builder.env,
227 builder.target.getAssociatedRule(),
228 builder.configuration,
229 builder.prerequisiteMap.get(null),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100230 builder.visibility);
lpino5fe7ed02018-07-18 05:55:23 -0700231 this.rule = builder.target.getAssociatedRule();
dslomov44d15712017-12-20 05:42:28 -0800232 this.aspects = builder.aspects;
233 this.aspectDescriptors =
234 builder
235 .aspects
236 .stream()
237 .map(a -> a.getDescriptor())
238 .collect(ImmutableList.toImmutableList());
Michael Staibb51251e2015-09-29 23:31:51 +0000239 this.configurationFragmentPolicy = builder.configurationFragmentPolicy;
lberki78651d42018-04-06 01:52:58 -0700240 this.universalFragments = universalFragments;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100241 this.targetMap = targetMap;
242 this.filesetEntryMap = filesetEntryMap;
243 this.configConditions = configConditions;
Greg Estren7f534232016-12-01 21:38:25 +0000244 this.attributes = new AspectAwareAttributeMapper(attributes, aspectAttributes);
Googler993f1de2018-02-20 02:31:10 -0800245 Set<String> allEnabledFeatures = new HashSet<>();
246 Set<String> allDisabledFeatures = new HashSet<>();
247 getAllFeatures(allEnabledFeatures, allDisabledFeatures);
248 this.enabledFeatures = ImmutableSortedSet.copyOf(allEnabledFeatures);
249 this.disabledFeatures = ImmutableSortedSet.copyOf(allDisabledFeatures);
Michael Staib8824d5e2016-01-20 21:37:05 +0000250 this.ruleClassNameForLogging = ruleClassNameForLogging;
Greg Estren9eb1cf02015-06-26 22:18:35 +0000251 this.hostConfiguration = builder.hostConfiguration;
janakreaff19c2019-01-31 13:59:40 -0800252 this.actionOwnerSymbolGenerator = new SymbolGenerator<>(actionLookupKey);
Florian Weikertb8a6a942015-09-25 12:36:08 +0000253 reporter = builder.reporter;
juliexxiab5f9d742020-04-09 13:07:13 -0700254 this.toolchainContexts = toolchainContexts;
gregce6acfe4e2018-05-25 08:38:39 -0700255 this.constraintSemantics = constraintSemantics;
gregce966dc232019-10-18 15:34:07 -0700256 this.requiredConfigFragments = requiredConfigFragments;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100257 }
258
Googler993f1de2018-02-20 02:31:10 -0800259 private void getAllFeatures(Set<String> allEnabledFeatures, Set<String> allDisabledFeatures) {
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000260 Set<String> globallyEnabled = new HashSet<>();
261 Set<String> globallyDisabled = new HashSet<>();
262 parseFeatures(getConfiguration().getDefaultFeatures(), globallyEnabled, globallyDisabled);
263 Set<String> packageEnabled = new HashSet<>();
264 Set<String> packageDisabled = new HashSet<>();
265 parseFeatures(getRule().getPackage().getFeatures(), packageEnabled, packageDisabled);
Googler8e3afcc2017-12-20 08:10:21 -0800266 Set<String> ruleEnabled = new HashSet<>();
267 Set<String> ruleDisabled = new HashSet<>();
268 if (attributes().has("features", Type.STRING_LIST)) {
269 parseFeatures(attributes().get("features", Type.STRING_LIST), ruleEnabled, ruleDisabled);
270 }
Googler993f1de2018-02-20 02:31:10 -0800271
Googler8e3afcc2017-12-20 08:10:21 -0800272 Set<String> ruleDisabledFeatures =
273 Sets.union(ruleDisabled, Sets.difference(packageDisabled, ruleEnabled));
Googler993f1de2018-02-20 02:31:10 -0800274 allDisabledFeatures.addAll(Sets.union(ruleDisabledFeatures, globallyDisabled));
Googler993f1de2018-02-20 02:31:10 -0800275
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000276 Set<String> packageFeatures =
277 Sets.difference(Sets.union(globallyEnabled, packageEnabled), packageDisabled);
Googler8e3afcc2017-12-20 08:10:21 -0800278 Set<String> ruleFeatures =
279 Sets.difference(Sets.union(packageFeatures, ruleEnabled), ruleDisabled);
Googler993f1de2018-02-20 02:31:10 -0800280 allEnabledFeatures.addAll(Sets.difference(ruleFeatures, globallyDisabled));
Manuel Klimek6d9fb362015-04-30 12:50:55 +0000281 }
282
283 private void parseFeatures(Iterable<String> features, Set<String> enabled, Set<String> disabled) {
284 for (String feature : features) {
285 if (feature.startsWith("-")) {
286 disabled.add(feature.substring(1));
287 } else if (feature.equals("no_layering_check")) {
288 // TODO(bazel-team): Remove once we do not have BUILD files left that contain
289 // 'no_layering_check'.
290 disabled.add(feature.substring(3));
291 } else {
292 enabled.add(feature);
293 }
294 }
295 }
296
dslomovfd62e762017-09-19 16:55:53 +0200297 public RepositoryName getRepository() {
298 return rule.getRepository();
299 }
300
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100301 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800302 public ArtifactRoot getBinDirectory() {
dslomovfd62e762017-09-19 16:55:53 +0200303 return getConfiguration().getBinDirectory(rule.getRepository());
304 }
305
306 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800307 public ArtifactRoot getMiddlemanDirectory() {
dslomovfd62e762017-09-19 16:55:53 +0200308 return getConfiguration().getMiddlemanDirectory(rule.getRepository());
309 }
cparsons88821922017-10-11 01:21:46 +0200310
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100311 public Rule getRule() {
312 return rule;
313 }
314
dslomov44d15712017-12-20 05:42:28 -0800315 public ImmutableList<Aspect> getAspects() {
316 return aspects;
317 }
318
319 /**
cparsonse8d450c2018-10-04 16:01:53 -0700320 * If this target's configuration suppresses analysis failures, this returns a list
321 * of strings, where each string corresponds to a description of an error that occurred during
322 * processing this target.
323 *
324 * @throws IllegalStateException if this target's configuration does not suppress analysis
325 * failures (if {@code getConfiguration().allowAnalysisFailures()} is false)
326 */
327 public List<String> getSuppressedErrorMessages() {
328 Preconditions.checkState(getConfiguration().allowAnalysisFailures(),
329 "Error messages can only be retrieved via RuleContext if allow_analysis_failures is true");
330 Preconditions.checkState(reporter instanceof SuppressingErrorReporter,
331 "Unexpected error reporter");
332 return ((SuppressingErrorReporter) reporter).getErrorMessages();
333 }
334
335 /**
dslomov44d15712017-12-20 05:42:28 -0800336 * If this <code>RuleContext</code> is for an aspect implementation, returns that aspect.
337 * (it is the last aspect in the list of aspects applied to a target; all other aspects
338 * are the ones main aspect sees as specified by its "required_aspect_providers")
339 * Otherwise returns <code>null</code>.
340 */
341 @Nullable
342 public Aspect getMainAspect() {
343 return aspects.isEmpty() ? null : aspects.get(aspects.size() - 1);
344 }
345
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100346 /**
Michael Staib8824d5e2016-01-20 21:37:05 +0000347 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
348 */
349 public String getRuleClassNameForLogging() {
350 return ruleClassNameForLogging;
351 }
352
353 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +0000354 * Returns the workspace name for the rule.
355 */
356 public String getWorkspaceName() {
kchodorow85ae1902017-04-22 15:07:22 -0400357 return rule.getRepository().strippedName();
Kristina Chodorow91876f02015-02-27 17:14:12 +0000358 }
359
360 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100361 * The configuration conditions that trigger this rule's configurable attributes.
362 */
gregce593f7f92017-09-19 02:02:21 +0200363 public ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100364 return configConditions;
365 }
366
367 /**
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000368 * Returns the host configuration for this rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100369 */
370 public BuildConfiguration getHostConfiguration() {
Greg Estren9eb1cf02015-06-26 22:18:35 +0000371 return hostConfiguration;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100372 }
373
374 /**
Dmitry Lomov503c2f72017-02-23 08:55:47 +0000375 * All aspects applied to the rule.
376 */
377 public ImmutableList<AspectDescriptor> getAspectDescriptors() {
378 return aspectDescriptors;
379 }
380
381 /**
Greg Estren7f534232016-12-01 21:38:25 +0000382 * Accessor for the attributes of the rule and its aspects.
383 *
384 * <p>The rule's native attributes can be queried both on their structure / existence and values
385 * Aspect attributes can only be queried on their structure.
386 *
387 * <p>This should be the sole interface for reading rule/aspect attributes in {@link RuleContext}.
388 * Don't expose other access points through new public methods.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100389 */
390 public AttributeMap attributes() {
391 return attributes;
392 }
393
cparsons0dcffc52017-10-13 23:40:31 +0200394 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100395 public boolean hasErrors() {
cparsons146b9ff2019-06-21 09:45:14 -0700396 return reporter.hasErrors();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100397 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000398
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100399 /**
400 * Returns an immutable map from attribute name to list of configured targets for that attribute.
401 */
402 public ListMultimap<String, ? extends TransitiveInfoCollection> getConfiguredTargetMap() {
janakr9c101402018-03-10 06:48:59 -0800403 return Multimaps.transformValues(targetMap, ConfiguredTargetAndData::getConfiguredTarget);
janakrf3e6f252018-01-18 07:45:12 -0800404 }
405
janakr65866212018-03-10 22:30:33 -0800406 /**
407 * Returns an immutable map from attribute name to list of {@link ConfiguredTargetAndData} objects
408 * for that attribute.
409 */
410 public ListMultimap<String, ConfiguredTargetAndData> getConfiguredTargetAndDataMap() {
411 return targetMap;
412 }
413
janakr9c101402018-03-10 06:48:59 -0800414 private List<ConfiguredTargetAndData> getConfiguredTargetAndTargetDeps(String key) {
mjhalupkade47f212018-02-12 12:31:21 -0800415 return targetMap.get(key);
416 }
417
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100418 /**
419 * Returns an immutable map from attribute name to list of fileset entries.
420 */
421 public ListMultimap<String, ConfiguredFilesetEntry> getFilesetEntryMap() {
422 return filesetEntryMap;
423 }
424
425 @Override
426 public ActionOwner getActionOwner() {
427 if (actionOwner == null) {
John Caterec5d2ed2018-01-04 11:52:21 -0800428 actionOwner =
Googlerb5082462019-08-26 14:28:09 -0700429 createActionOwner(
430 rule,
431 aspectDescriptors,
432 getConfiguration(),
433 getTargetExecProperties(),
434 getExecutionPlatform());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100435 }
436 return actionOwner;
437 }
438
439 /**
plf1f341a62019-04-01 14:02:14 -0700440 * We have to re-implement this method here because it is declared in the interface {@link
441 * ActionConstructionContext}. This class inherits from {@link TargetContext} which doesn't
442 * implement the {@link ActionConstructionContext} interface.
443 */
444 @Override
445 public ActionKeyContext getActionKeyContext() {
446 return super.getActionKeyContext();
447 }
448
449 /**
janakreaff19c2019-01-31 13:59:40 -0800450 * An opaque symbol generator to be used when identifying objects by their action owner/index of
451 * creation. Only needed if an object needs to know whether it was created by the same action
452 * owner in the same order as another object. Each symbol must call {@link
453 * SymbolGenerator#generate} separately to obtain a unique object.
454 */
455 public SymbolGenerator<?> getSymbolGenerator() {
456 return actionOwnerSymbolGenerator;
457 }
458
459 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100460 * Returns a configuration fragment for this this target.
461 */
462 @Nullable
gregcebe55e112018-01-30 11:04:53 -0800463 public <T extends Fragment> T getFragment(Class<T> fragment, ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800464 return getFragment(fragment, fragment.getSimpleName(), "", transition);
Florian Weikertd2a24612015-09-07 14:35:23 +0000465 }
466
467 @Nullable
468 protected <T extends Fragment> T getFragment(Class<T> fragment, String name,
gregcebe55e112018-01-30 11:04:53 -0800469 String additionalErrorMessage, ConfigurationTransition transition) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100470 // TODO(bazel-team): The fragments can also be accessed directly through BuildConfiguration.
471 // Can we lock that down somehow?
gregcec7b21212017-12-21 12:40:20 -0800472 Preconditions.checkArgument(isLegalFragment(fragment, transition),
Florian Weikertd2a24612015-09-07 14:35:23 +0000473 "%s has to declare '%s' as a required fragment "
474 + "in %s configuration in order to access it.%s",
gregcec7b21212017-12-21 12:40:20 -0800475 getRuleClassNameForLogging(), name, FragmentCollection.getConfigurationName(transition),
Florian Weikertd2a24612015-09-07 14:35:23 +0000476 additionalErrorMessage);
gregcec7b21212017-12-21 12:40:20 -0800477 return getConfiguration(transition).getFragment(fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100478 }
479
Florian Weikert082c0542015-08-06 10:24:29 +0000480 @Nullable
Florian Weikert3f8aac92015-09-07 12:06:02 +0000481 public <T extends Fragment> T getFragment(Class<T> fragment) {
gregce7fa23ea2018-01-18 12:46:04 -0800482 // No transition means target configuration.
483 return getFragment(fragment, NoTransition.INSTANCE);
Florian Weikert082c0542015-08-06 10:24:29 +0000484 }
485
Florian Weikert3f8aac92015-09-07 12:06:02 +0000486 @Nullable
adonovanb8eae2d2019-12-09 15:11:06 -0800487 public Fragment getSkylarkFragment(String name, ConfigurationTransition transition)
488 throws EvalException {
Florian Weikert1c2eeac2015-10-28 10:00:53 +0000489 Class<? extends Fragment> fragmentClass =
gregcec7b21212017-12-21 12:40:20 -0800490 getConfiguration(transition).getSkylarkFragmentByName(name);
Florian Weikertd2a24612015-09-07 14:35:23 +0000491 if (fragmentClass == null) {
492 return null;
493 }
adonovanb8eae2d2019-12-09 15:11:06 -0800494 try {
495 return getFragment(
496 fragmentClass,
497 name,
498 String.format(
499 " Please update the '%1$sfragments' argument of the rule definition "
500 + "(for example: %1$sfragments = [\"%2$s\"])",
501 transition.isHostTransition() ? "host_" : "", name),
502 transition);
503 } catch (IllegalArgumentException ex) { // fishy
504 throw new EvalException(null, ex.getMessage());
505 }
Florian Weikert3f8aac92015-09-07 12:06:02 +0000506 }
507
gregcebe55e112018-01-30 11:04:53 -0800508 public ImmutableCollection<String> getSkylarkFragmentNames(ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800509 return getConfiguration(transition).getSkylarkFragmentNames();
Florian Weikert3f8aac92015-09-07 12:06:02 +0000510 }
511
512 public <T extends Fragment> boolean isLegalFragment(
gregcebe55e112018-01-30 11:04:53 -0800513 Class<T> fragment, ConfigurationTransition transition) {
lberki78651d42018-04-06 01:52:58 -0700514 return universalFragments.contains(fragment)
gregcec7b21212017-12-21 12:40:20 -0800515 || configurationFragmentPolicy.isLegalConfigurationFragment(fragment, transition);
Florian Weikert082c0542015-08-06 10:24:29 +0000516 }
517
Ulf Adamsea11fc52015-08-04 14:23:58 +0000518 public <T extends Fragment> boolean isLegalFragment(Class<T> fragment) {
gregce7fa23ea2018-01-18 12:46:04 -0800519 // No transition means target configuration.
520 return isLegalFragment(fragment, NoTransition.INSTANCE);
Florian Weikert3f8aac92015-09-07 12:06:02 +0000521 }
Florian Weikertd2a24612015-09-07 14:35:23 +0000522
gregcee861ffc2018-02-02 17:06:49 -0800523 private BuildConfiguration getConfiguration(ConfigurationTransition transition) {
gregcec7b21212017-12-21 12:40:20 -0800524 return transition.isHostTransition() ? hostConfiguration : getConfiguration();
Ulf Adamsea11fc52015-08-04 14:23:58 +0000525 }
526
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100527 @Override
janakr658d47f2019-05-29 11:11:30 -0700528 public ActionLookupValue.ActionLookupKey getOwner() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100529 return getAnalysisEnvironment().getOwner();
530 }
531
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000532 public ImmutableList<Artifact> getBuildInfo(BuildInfoKey key) throws InterruptedException {
plf1f341a62019-04-01 14:02:14 -0700533 return getAnalysisEnvironment()
534 .getBuildInfo(
535 AnalysisUtils.isStampingEnabled(this, getConfiguration()), key, getConfiguration());
Ulf Adamsc272e0f2015-04-22 19:56:21 +0000536 }
537
Googlerb5082462019-08-26 14:28:09 -0700538 private static ImmutableMap<String, String> computeExecProperties(
539 Map<String, String> targetExecProperties, @Nullable PlatformInfo executionPlatform) {
540 Map<String, String> execProperties = new HashMap<>();
541
542 if (executionPlatform != null) {
543 execProperties.putAll(executionPlatform.execProperties());
544 }
545
546 // If the same key occurs both in the platform and in target-specific properties, the
547 // value is taken from target-specific properties (effectively overriding the platform
548 // properties).
549 execProperties.putAll(targetExecProperties);
550 return ImmutableMap.copyOf(execProperties);
551 }
552
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000553 @VisibleForTesting
Carmi Grushko33aa3062016-11-11 02:45:29 +0000554 public static ActionOwner createActionOwner(
555 Rule rule,
Dmitry Lomov15756522016-12-16 16:52:37 +0000556 ImmutableList<AspectDescriptor> aspectDescriptors,
John Caterec5d2ed2018-01-04 11:52:21 -0800557 BuildConfiguration configuration,
Googlerb5082462019-08-26 14:28:09 -0700558 Map<String, String> targetExecProperties,
John Caterec5d2ed2018-01-04 11:52:21 -0800559 @Nullable PlatformInfo executionPlatform) {
Carmi Grushko4665e702016-11-09 21:51:27 +0000560 return ActionOwner.create(
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000561 rule.getLabel(),
Dmitry Lomov15756522016-12-16 16:52:37 +0000562 aspectDescriptors,
Janak Ramakrishnan7857c792016-03-21 08:35:35 +0000563 rule.getLocation(),
564 configuration.getMnemonic(),
565 rule.getTargetKind(),
566 configuration.checksum(),
shahan50f99d52018-03-10 05:14:09 -0800567 configuration.toBuildEvent(),
John Caterec5d2ed2018-01-04 11:52:21 -0800568 configuration.isHostConfiguration() ? HOST_CONFIGURATION_PROGRESS_TAG : null,
Googlerb5082462019-08-26 14:28:09 -0700569 computeExecProperties(targetExecProperties, executionPlatform),
John Caterec5d2ed2018-01-04 11:52:21 -0800570 executionPlatform);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100571 }
572
573 @Override
Rumou Duan33bab462016-04-25 17:55:12 +0000574 public void registerAction(ActionAnalysisMetadata... action) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100575 getAnalysisEnvironment().registerAction(action);
576 }
577
578 /**
579 * Convenience function for subclasses to report non-attribute-specific
580 * errors in the current rule.
581 */
582 @Override
583 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000584 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100585 }
Michajlo Matijkiwe64bfce2016-07-18 14:37:08 +0000586
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100587 /**
588 * Convenience function for subclasses to report non-attribute-specific
589 * warnings in the current rule.
590 */
591 @Override
592 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000593 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100594 }
595
596 /**
597 * Convenience function for subclasses to report attribute-specific errors in
598 * the current rule.
599 *
600 * <p>If the name of the attribute starts with <code>$</code>
601 * it is replaced with a string <code>(an implicit dependency)</code>.
602 */
603 @Override
604 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000605 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100606 }
607
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000608 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100609 * Like attributeError, but does not mark the configured target as errored.
610 *
611 * <p>If the name of the attribute starts with <code>$</code>
612 * it is replaced with a string <code>(an implicit dependency)</code>.
613 */
614 @Override
615 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +0000616 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100617 }
618
619 /**
620 * Returns an artifact beneath the root of either the "bin" or "genfiles"
621 * tree, whose path is based on the name of this target and the current
622 * configuration. The choice of which tree to use is based on the rule with
623 * which this target (which must be an OutputFile or a Rule) is associated.
624 */
625 public Artifact createOutputArtifact() {
cparsons0623d3c2018-10-23 16:06:30 -0700626 Target target = getTarget();
627 PathFragment rootRelativePath = getPackageDirectory()
628 .getRelative(PathFragment.create(target.getName()));
629
630 return internalCreateOutputArtifact(rootRelativePath, target, OutputFile.Kind.FILE);
631 }
632
633 /**
634 * Returns an artifact beneath the root of either the "bin" or "genfiles"
635 * tree, whose path is based on the name of this target and the current
636 * configuration, with a script suffix appropriate for the current host platform. ({@code .cmd}
637 * for Windows, otherwise {@code .sh}). The choice of which tree to use is based on the rule with
638 * which this target (which must be an OutputFile or a Rule) is associated.
639 */
640 public Artifact createOutputArtifactScript() {
641 Target target = getTarget();
642 // TODO(laszlocsomor): Use the execution platform, not the host platform.
643 boolean isExecutedOnWindows = OS.getCurrent() == OS.WINDOWS;
644
645 String fileExtension = isExecutedOnWindows ? ".cmd" : ".sh";
646
647 PathFragment rootRelativePath = getPackageDirectory()
648 .getRelative(PathFragment.create(target.getName() + fileExtension));
649
650 return internalCreateOutputArtifact(rootRelativePath, target, OutputFile.Kind.FILE);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100651 }
652
653 /**
654 * Returns the output artifact of an {@link OutputFile} of this target.
655 *
656 * @see #createOutputArtifact()
657 */
658 public Artifact createOutputArtifact(OutputFile out) {
cparsons0623d3c2018-10-23 16:06:30 -0700659 PathFragment packageRelativePath = getPackageDirectory()
660 .getRelative(PathFragment.create(out.getName()));
661 return internalCreateOutputArtifact(packageRelativePath, out, out.getKind());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100662 }
663
664 /**
665 * Implementation for {@link #createOutputArtifact()} and
666 * {@link #createOutputArtifact(OutputFile)}. This is private so that
667 * {@link #createOutputArtifact(OutputFile)} can have a more specific
668 * signature.
669 */
cparsons0623d3c2018-10-23 16:06:30 -0700670 private Artifact internalCreateOutputArtifact(PathFragment rootRelativePath,
671 Target target, OutputFile.Kind outputFileKind) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000672 Preconditions.checkState(
673 target.getLabel().getPackageIdentifier().equals(getLabel().getPackageIdentifier()),
674 "Creating output artifact for target '%s' in different package than the rule '%s' "
675 + "being analyzed", target.getLabel(), getLabel());
tomlu1cdcdf92018-01-16 11:07:51 -0800676 ArtifactRoot root = getBinOrGenfilesDirectory();
cparsons0623d3c2018-10-23 16:06:30 -0700677
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700678 switch (outputFileKind) {
679 case FILE:
cparsons0623d3c2018-10-23 16:06:30 -0700680 return getDerivedArtifact(rootRelativePath, root);
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700681 case FILESET:
cparsons0623d3c2018-10-23 16:06:30 -0700682 return getAnalysisEnvironment().getFilesetArtifact(rootRelativePath, root);
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700683 default:
684 throw new IllegalStateException();
685 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100686 }
687
688 /**
tomlu1cdcdf92018-01-16 11:07:51 -0800689 * Returns the root of either the "bin" or "genfiles" tree, based on this target and the current
690 * configuration. The choice of which tree to use is based on the rule with which this target
691 * (which must be an OutputFile or a Rule) is associated.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100692 */
tomlu1cdcdf92018-01-16 11:07:51 -0800693 public ArtifactRoot getBinOrGenfilesDirectory() {
Kristina Chodorowba41c2d2016-10-10 17:21:24 +0000694 return rule.hasBinaryOutput()
695 ? getConfiguration().getBinDirectory(rule.getRepository())
696 : getConfiguration().getGenfilesDirectory(rule.getRepository());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100697 }
698
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000699 /**
tomlu1cdcdf92018-01-16 11:07:51 -0800700 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
701 * guaranteeing that it never clashes with artifacts created by rules in other packages.
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000702 */
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000703 public Artifact getBinArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000704 return getBinArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000705 }
706
707 public Artifact getBinArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000708 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000709 relative, getConfiguration().getBinDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000710 }
711
712 /**
713 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
714 * guaranteeing that it never clashes with artifacts created by rules in other packages.
715 */
716 public Artifact getGenfilesArtifact(String relative) {
nharmatab4060b62017-04-04 17:11:39 +0000717 return getGenfilesArtifact(PathFragment.create(relative));
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000718 }
719
720 public Artifact getGenfilesArtifact(PathFragment relative) {
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000721 return getPackageRelativeArtifact(
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000722 relative, getConfiguration().getGenfilesDirectory(rule.getRepository()));
Carmi Grushkof414b4e2016-06-23 20:35:27 +0000723 }
724
plfb74df042018-10-31 02:15:10 -0700725 @Override
tomlu1cdcdf92018-01-16 11:07:51 -0800726 public Artifact getShareableArtifact(PathFragment rootRelativePath, ArtifactRoot root) {
Lukacs Berki21a04f22015-08-20 13:31:24 +0000727 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root);
728 }
729
asteinb0de45462018-05-17 08:07:12 -0700730 @Override
janakr658d47f2019-05-29 11:11:30 -0700731 public Artifact.DerivedArtifact getPackageRelativeArtifact(
732 PathFragment relative, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700733 return getPackageRelativeArtifact(relative, root, /*contentBasedPath=*/ false);
734 }
735
736 /**
737 * Same as {@link #getPackageRelativeArtifact(PathFragment, ArtifactRoot)} but includes the option
738 * option to use a content-based path for this artifact (see {@link
739 * BuildConfiguration#useContentBasedOutputPaths()}).
740 */
741 private Artifact.DerivedArtifact getPackageRelativeArtifact(
742 PathFragment relative, ArtifactRoot root, boolean contentBasedPath) {
743 return getDerivedArtifact(getPackageDirectory().getRelative(relative), root, contentBasedPath);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000744 }
745
janakr658d47f2019-05-29 11:11:30 -0700746 /**
747 * Creates an artifact in a directory that is unique to the package that contains the rule, thus
748 * guaranteeing that it never clashes with artifacts created by rules in other packages.
749 */
750 public Artifact getPackageRelativeArtifact(String relative, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700751 return getPackageRelativeArtifact(relative, root, /*contentBasedPath=*/ false);
752 }
753
754 /**
755 * Same as {@link #getPackageRelativeArtifact(String, ArtifactRoot)} but includes the option to
756 * use a content-based path for this artifact (see {@link
757 * BuildConfiguration#useContentBasedOutputPaths()}).
758 */
759 private Artifact getPackageRelativeArtifact(
760 String relative, ArtifactRoot root, boolean contentBasedPath) {
761 return getPackageRelativeArtifact(PathFragment.create(relative), root, contentBasedPath);
janakr658d47f2019-05-29 11:11:30 -0700762 }
763
asteinb0de45462018-05-17 08:07:12 -0700764 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000765 public PathFragment getPackageDirectory() {
Dmitry Lomove36a66c2017-02-17 14:48:48 +0000766 return getLabel().getPackageIdentifier().getSourceRoot();
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000767 }
768
769 /**
770 * Creates an artifact under a given root with the given root-relative path.
771 *
772 * <p>Verifies that it is in the root-relative directory corresponding to the package of the rule,
773 * thus ensuring that it doesn't clash with other artifacts generated by other rules using this
774 * method.
775 */
Ulf Adams3ab82f72015-09-04 12:10:53 +0000776 @Override
janakr658d47f2019-05-29 11:11:30 -0700777 public Artifact.DerivedArtifact getDerivedArtifact(
778 PathFragment rootRelativePath, ArtifactRoot root) {
gregce11f3b0e2019-06-07 17:12:06 -0700779 return getDerivedArtifact(rootRelativePath, root, /*contentBasedPath=*/ false);
780 }
781
782 /**
783 * Same as {@link #getDerivedArtifact(PathFragment, ArtifactRoot)} but includes the option to use
784 * a content-based path for this artifact (see {@link
785 * BuildConfiguration#useContentBasedOutputPaths()}).
786 */
787 public Artifact.DerivedArtifact getDerivedArtifact(
788 PathFragment rootRelativePath, ArtifactRoot root, boolean contentBasedPath) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000789 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
790 "Output artifact '%s' not under package directory '%s' for target '%s'",
791 rootRelativePath, getPackageDirectory(), getLabel());
gregce11f3b0e2019-06-07 17:12:06 -0700792 return getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, root, contentBasedPath);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000793 }
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000794
plf441fd752019-02-06 01:28:18 -0800795 @Override
cpeyserac09f0a2018-02-05 09:33:15 -0800796 public SpecialArtifact getTreeArtifact(PathFragment rootRelativePath, ArtifactRoot root) {
Michael Thvedte3b1cb72016-02-08 23:32:27 +0000797 Preconditions.checkState(rootRelativePath.startsWith(getPackageDirectory()),
798 "Output artifact '%s' not under package directory '%s' for target '%s'",
799 rootRelativePath, getPackageDirectory(), getLabel());
800 return getAnalysisEnvironment().getTreeArtifact(rootRelativePath, root);
801 }
802
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000803 /**
allevato060a4482017-03-30 20:45:52 +0000804 * Creates a tree artifact in a directory that is unique to the package that contains the rule,
805 * thus guaranteeing that it never clashes with artifacts created by rules in other packages.
806 */
tomlu1cdcdf92018-01-16 11:07:51 -0800807 public Artifact getPackageRelativeTreeArtifact(PathFragment relative, ArtifactRoot root) {
allevato060a4482017-03-30 20:45:52 +0000808 return getTreeArtifact(getPackageDirectory().getRelative(relative), root);
809 }
810
811 /**
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000812 * Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
813 * clashes with artifacts created by other rules.
814 */
815 public Artifact getUniqueDirectoryArtifact(
tomlu1cdcdf92018-01-16 11:07:51 -0800816 String uniqueDirectory, String relative, ArtifactRoot root) {
nharmatab4060b62017-04-04 17:11:39 +0000817 return getUniqueDirectoryArtifact(uniqueDirectory, PathFragment.create(relative), root);
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000818 }
819
asteinb0de45462018-05-17 08:07:12 -0700820 @Override
821 public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String relative) {
822 return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
823 }
824
ahumesky4b00ab12018-11-15 16:23:46 -0800825 @Override
826 public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
827 return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
828 }
829
plf727a07d2019-02-01 02:27:35 -0800830 @Override
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000831 public Artifact getUniqueDirectoryArtifact(
tomlu1cdcdf92018-01-16 11:07:51 -0800832 String uniqueDirectory, PathFragment relative, ArtifactRoot root) {
Lukacs Berki4a89a9b2015-07-29 06:54:07 +0000833 return getDerivedArtifact(getUniqueDirectory(uniqueDirectory).getRelative(relative), root);
834 }
835
Googler03083852015-12-06 18:31:53 +0000836 /**
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000837 * Returns true iff the rule, or any attached aspect, has an attribute with the given name and
838 * type.
839 */
840 public boolean isAttrDefined(String attrName, Type<?> type) {
Greg Estren7f534232016-12-01 21:38:25 +0000841 return attributes().has(attrName, type);
Carmi Grushko8e589dc2016-12-01 02:28:42 +0000842 }
843
844 /**
Lukacs Berki8bdae762016-07-13 14:58:54 +0000845 * Returns the dependencies through a {@code LABEL_DICT_UNARY} attribute as a map from
846 * a string to a {@link TransitiveInfoCollection}.
847 */
848 public Map<String, TransitiveInfoCollection> getPrerequisiteMap(String attributeName) {
Greg Estren7f534232016-12-01 21:38:25 +0000849 Preconditions.checkState(attributes().has(attributeName, BuildType.LABEL_DICT_UNARY));
Lukacs Berki8bdae762016-07-13 14:58:54 +0000850
851 ImmutableMap.Builder<String, TransitiveInfoCollection> result = ImmutableMap.builder();
852 Map<String, Label> dict = attributes().get(attributeName, BuildType.LABEL_DICT_UNARY);
853 Map<Label, ConfiguredTarget> labelToDep = new HashMap<>();
janakr9c101402018-03-10 06:48:59 -0800854 for (ConfiguredTargetAndData dep : targetMap.get(attributeName)) {
janakrf3e6f252018-01-18 07:45:12 -0800855 labelToDep.put(dep.getTarget().getLabel(), dep.getConfiguredTarget());
Lukacs Berki8bdae762016-07-13 14:58:54 +0000856 }
857
858 for (Map.Entry<String, Label> entry : dict.entrySet()) {
859 result.put(entry.getKey(), Preconditions.checkNotNull(labelToDep.get(entry.getValue())));
860 }
861
862 return result.build();
863 }
864
865 /**
Googler46b285a2020-03-06 13:33:24 -0800866 * Returns the prerequisites keyed by their configuration transition keys. If the split transition
mjhalupkade47f212018-02-12 12:31:21 -0800867 * is not active (e.g. split() returned an empty list), the key is an empty Optional.
868 */
869 public Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>>
870 getSplitPrerequisites(String attributeName) {
871 return Maps.transformValues(
872 getSplitPrerequisiteConfiguredTargetAndTargets(attributeName),
janakr9c101402018-03-10 06:48:59 -0800873 (ctatList) -> Lists.transform(ctatList, ConfiguredTargetAndData::getConfiguredTarget));
mjhalupkade47f212018-02-12 12:31:21 -0800874 }
875
876 /**
877 * Returns the list of ConfiguredTargetsAndTargets that feed into the target through the specified
878 * attribute. Note that you need to specify the correct mode for the attribute otherwise an
879 * exception will be raised.
880 */
janakr9c101402018-03-10 06:48:59 -0800881 public List<ConfiguredTargetAndData> getPrerequisiteConfiguredTargetAndTargets(
mjhalupkade47f212018-02-12 12:31:21 -0800882 String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +0000883 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
jcatere8f5a982019-04-02 11:12:19 -0700884 if ((mode == Mode.TARGET) && (attributeDefinition.getTransitionFactory().isSplit())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100885 // TODO(bazel-team): If you request a split-configured attribute in the target configuration,
886 // we return only the list of configured targets for the first architecture; this is for
887 // backwards compatibility with existing code in cases where the call to getPrerequisites is
888 // deeply nested and we can't easily inject the behavior we want. However, we should fix all
889 // such call sites.
890 checkAttribute(attributeName, Mode.SPLIT);
janakr9c101402018-03-10 06:48:59 -0800891 Map<Optional<String>, List<ConfiguredTargetAndData>> map =
mjhalupkade47f212018-02-12 12:31:21 -0800892 getSplitPrerequisiteConfiguredTargetAndTargets(attributeName);
dslomovde965ac2017-07-31 21:07:51 +0200893 return map.isEmpty() ? ImmutableList.of() : map.entrySet().iterator().next().getValue();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100894 }
895
896 checkAttribute(attributeName, mode);
mjhalupkade47f212018-02-12 12:31:21 -0800897 return getConfiguredTargetAndTargetDeps(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100898 }
899
janakr0758d352018-03-10 20:38:45 -0800900 /**
Googler46b285a2020-03-06 13:33:24 -0800901 * Returns the prerequisites keyed by their transition keys. If the split transition is not active
902 * (e.g. split() returned an empty list), the key is an empty Optional.
janakr0758d352018-03-10 20:38:45 -0800903 */
904 public Map<Optional<String>, List<ConfiguredTargetAndData>>
mjhalupkade47f212018-02-12 12:31:21 -0800905 getSplitPrerequisiteConfiguredTargetAndTargets(String attributeName) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100906 checkAttribute(attributeName, Mode.SPLIT);
Greg Estren7f534232016-12-01 21:38:25 +0000907 Attribute attributeDefinition = attributes().getAttributeDefinition(attributeName);
jcatere8f5a982019-04-02 11:12:19 -0700908 Preconditions.checkState(attributeDefinition.getTransitionFactory().isSplit());
mjhalupkade47f212018-02-12 12:31:21 -0800909 SplitTransition transition =
John Cater5adcd3e2019-03-28 10:14:32 -0700910 (SplitTransition)
911 attributeDefinition
912 .getTransitionFactory()
913 .create(
jcater23589462019-05-20 08:51:24 -0700914 AttributeTransitionData.builder()
915 .attributes(ConfiguredAttributeMapper.of(rule, configConditions))
916 .executionPlatform(getToolchainContext().executionPlatform().label())
917 .build());
gregce1cc0dec2018-05-23 12:44:23 -0700918 BuildOptions fromOptions = getConfiguration().getOptions();
gregcef0a40ac2020-03-31 14:11:30 -0700919 Map<String, BuildOptions> splitOptions =
920 transition.split(fromOptions, getAnalysisEnvironment().getEventHandler());
janakr9c101402018-03-10 06:48:59 -0800921 List<ConfiguredTargetAndData> deps = getConfiguredTargetAndTargetDeps(attributeName);
mjhalupkade47f212018-02-12 12:31:21 -0800922
Googler19226b72020-02-06 12:58:43 -0800923 if (SplitTransition.equals(fromOptions, splitOptions.values())) {
Googler46b285a2020-03-06 13:33:24 -0800924 // The split transition is not active.
Greg Estren66cadd32016-08-05 21:07:02 +0000925 return ImmutableMap.of(Optional.<String>absent(), deps);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100926 }
927
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100928 // Use an ImmutableListMultimap.Builder here to preserve ordering.
janakr9c101402018-03-10 06:48:59 -0800929 ImmutableListMultimap.Builder<Optional<String>, ConfiguredTargetAndData> result =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100930 ImmutableListMultimap.builder();
janakr9c101402018-03-10 06:48:59 -0800931 for (ConfiguredTargetAndData t : deps) {
Googler46b285a2020-03-06 13:33:24 -0800932 if (t.getTransitionKey() == null
933 || t.getTransitionKey().equals(ConfigurationTransition.PATCH_TRANSITION_KEY)) {
934 // The target doesn't have a specific transition key associated. This likely means it's a
935 // non-configurable target, e.g. files, package groups. Pan out to all available keys.
936 for (String key : splitOptions.keySet()) {
937 result.put(Optional.of(key), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100938 }
Googler46b285a2020-03-06 13:33:24 -0800939 } else {
940 result.put(Optional.of(t.getTransitionKey()), t);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100941 }
942 }
943 return Multimaps.asMap(result.build());
944 }
945
946 /**
947 * Returns the specified provider of the prerequisite referenced by the attribute in the
948 * argument. Note that you need to specify the correct mode for the attribute, otherwise an
gregce47d57852017-06-26 23:01:54 +0200949 * assertion will be raised. If the attribute is empty or it does not support the specified
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100950 * provider, returns null.
951 */
952 public <C extends TransitiveInfoProvider> C getPrerequisite(
953 String attributeName, Mode mode, Class<C> provider) {
954 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
955 return prerequisite == null ? null : prerequisite.getProvider(provider);
956 }
957
958 /**
959 * Returns the transitive info collection that feeds into this target through the specified
960 * attribute. Note that you need to specify the correct mode for the attribute, otherwise an
961 * assertion will be raised. Returns null if the attribute is empty.
962 */
963 public TransitiveInfoCollection getPrerequisite(String attributeName, Mode mode) {
janakr27bb6dd2018-03-10 19:10:00 -0800964 ConfiguredTargetAndData result = getPrerequisiteConfiguredTargetAndData(attributeName, mode);
965 return result == null ? null : result.getConfiguredTarget();
966 }
967
968 /**
969 * Returns the {@link ConfiguredTargetAndData} that feeds ino this target through the specified
970 * attribute. Note that you need to specify the correct mode for the attribute, otherwise an
971 * assertion will be raised. Returns null if the attribute is empty.
972 */
973 public ConfiguredTargetAndData getPrerequisiteConfiguredTargetAndData(
974 String attributeName, Mode mode) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100975 checkAttribute(attributeName, mode);
janakr27bb6dd2018-03-10 19:10:00 -0800976 List<ConfiguredTargetAndData> elements = getConfiguredTargetAndTargetDeps(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100977 if (elements.size() > 1) {
Michael Staib8824d5e2016-01-20 21:37:05 +0000978 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
979 + " produces more than one prerequisite");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100980 }
981 return elements.isEmpty() ? null : elements.get(0);
982 }
983
984 /**
mjhalupkade47f212018-02-12 12:31:21 -0800985 * For a given attribute, returns all the ConfiguredTargetAndTargets of that attribute. Each
janakr9c101402018-03-10 06:48:59 -0800986 * ConfiguredTargetAndData is keyed by the {@link BuildConfiguration} that created it.
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000987 */
janakr9c101402018-03-10 06:48:59 -0800988 public ImmutableListMultimap<BuildConfiguration, ConfiguredTargetAndData>
mjhalupkade47f212018-02-12 12:31:21 -0800989 getPrerequisiteCofiguredTargetAndTargetsByConfiguration(String attributeName, Mode mode) {
janakr9c101402018-03-10 06:48:59 -0800990 List<ConfiguredTargetAndData> ctatCollection =
mjhalupkade47f212018-02-12 12:31:21 -0800991 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode);
janakr9c101402018-03-10 06:48:59 -0800992 ImmutableListMultimap.Builder<BuildConfiguration, ConfiguredTargetAndData> result =
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000993 ImmutableListMultimap.builder();
janakr9c101402018-03-10 06:48:59 -0800994 for (ConfiguredTargetAndData ctad : ctatCollection) {
janakr163b3922018-03-10 16:24:52 -0800995 result.put(ctad.getConfiguration(), ctad);
Chris Parsons4aa7c9d2016-04-07 19:29:02 +0000996 }
997 return result.build();
998 }
999
1000 /**
dslomovde965ac2017-07-31 21:07:51 +02001001 * For a given attribute, returns all declared provider provided by targets of that attribute.
1002 * Each declared provider is keyed by the {@link BuildConfiguration} under which the provider was
1003 * created.
cparsons075ab1e2018-08-07 14:20:20 -07001004 *
1005 * @deprecated use {@link #getPrerequisitesByConfiguration(String, Mode, BuiltinProvider)}
1006 * instead
1007 */
1008 @Deprecated
1009 public <C extends Info>
1010 ImmutableListMultimap<BuildConfiguration, C> getPrerequisitesByConfiguration(
1011 String attributeName, Mode mode, final NativeProvider<C> provider) {
1012 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
1013 ImmutableListMultimap.builder();
1014 for (ConfiguredTargetAndData prerequisite :
1015 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode)) {
1016 C prerequisiteProvider = prerequisite.getConfiguredTarget().get(provider);
1017 if (prerequisiteProvider != null) {
1018 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
1019 }
1020 }
1021 return result.build();
1022 }
1023
1024 /**
1025 * For a given attribute, returns all declared provider provided by targets of that attribute.
1026 * Each declared provider is keyed by the {@link BuildConfiguration} under which the provider was
1027 * created.
dslomov4e9fa192017-07-12 14:59:07 +02001028 */
dslomovde965ac2017-07-31 21:07:51 +02001029 public <C extends Info>
1030 ImmutableListMultimap<BuildConfiguration, C> getPrerequisitesByConfiguration(
cparsons075ab1e2018-08-07 14:20:20 -07001031 String attributeName, Mode mode, final BuiltinProvider<C> provider) {
dslomov4e9fa192017-07-12 14:59:07 +02001032 ImmutableListMultimap.Builder<BuildConfiguration, C> result =
1033 ImmutableListMultimap.builder();
janakr12b78fe2018-03-10 18:06:56 -08001034 for (ConfiguredTargetAndData prerequisite :
1035 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode)) {
1036 C prerequisiteProvider = prerequisite.getConfiguredTarget().get(provider);
dslomov4e9fa192017-07-12 14:59:07 +02001037 if (prerequisiteProvider != null) {
1038 result.put(prerequisite.getConfiguration(), prerequisiteProvider);
1039 }
1040 }
1041 return result.build();
1042 }
1043
1044 /**
Chris Parsons0d7f0412016-04-29 20:35:44 +00001045 * For a given attribute, returns all {@link TransitiveInfoCollection}s provided by targets
1046 * of that attribute. Each {@link TransitiveInfoCollection} is keyed by the
1047 * {@link BuildConfiguration} under which the collection was created.
1048 */
1049 public ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection>
1050 getPrerequisitesByConfiguration(String attributeName, Mode mode) {
Chris Parsons0d7f0412016-04-29 20:35:44 +00001051 ImmutableListMultimap.Builder<BuildConfiguration, TransitiveInfoCollection> result =
1052 ImmutableListMultimap.builder();
janakr12b78fe2018-03-10 18:06:56 -08001053 for (ConfiguredTargetAndData prerequisite :
1054 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode)) {
1055 result.put(prerequisite.getConfiguration(), prerequisite.getConfiguredTarget());
Chris Parsons0d7f0412016-04-29 20:35:44 +00001056 }
1057 return result.build();
1058 }
1059
1060 /**
cparsonsb35c0a42018-08-20 11:37:41 -07001061 * Returns the list of transitive info collections that feed into this target through the
1062 * specified attribute. Note that you need to specify the correct mode for the attribute,
1063 * otherwise an assertion will be raised.
1064 */
1065 public List<? extends TransitiveInfoCollection> getPrerequisites(String attributeName,
1066 Mode mode) {
1067 return Lists.transform(
1068 getPrerequisiteConfiguredTargetAndTargets(attributeName, mode),
1069 ConfiguredTargetAndData::getConfiguredTarget);
1070 }
1071
1072 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001073 * Returns all the providers of the specified type that are listed under the specified attribute
1074 * of this target in the BUILD file.
1075 */
ulfjack6c3908c2019-12-18 05:03:36 -08001076 public <C extends TransitiveInfoProvider> List<C> getPrerequisites(
1077 String attributeName, Mode mode, final Class<C> classType) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001078 AnalysisUtils.checkProvider(classType);
1079 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), classType);
1080 }
1081
1082 /**
Sergio Campamafd931432016-12-09 21:47:35 +00001083 * Returns all the declared providers (native and Skylark) for the specified constructor under the
1084 * specified attribute of this target in the BUILD file.
1085 */
ulfjack6c3908c2019-12-18 05:03:36 -08001086 public <T extends Info> List<T> getPrerequisites(
dslomovde965ac2017-07-31 21:07:51 +02001087 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
dslomov77baa4c2017-07-10 17:15:27 +02001088 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), skylarkKey);
Sergio Campamafd931432016-12-09 21:47:35 +00001089 }
1090
1091 /**
cparsons2d67cf92018-05-24 14:02:09 -07001092 * Returns all the declared providers (native and Skylark) for the specified constructor under the
1093 * specified attribute of this target in the BUILD file.
1094 */
ulfjack6c3908c2019-12-18 05:03:36 -08001095 public <T extends Info> List<T> getPrerequisites(
cparsons2d67cf92018-05-24 14:02:09 -07001096 String attributeName, Mode mode, final BuiltinProvider<T> skylarkKey) {
1097 return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), skylarkKey);
1098 }
1099
1100 /**
Sergio Campamae8cecd92016-12-13 18:49:28 +00001101 * Returns the declared provider (native and Skylark) for the specified constructor under the
1102 * specified attribute of this target in the BUILD file. May return null if there is no
1103 * TransitiveInfoCollection under the specified attribute.
1104 */
1105 @Nullable
adonovana11e2d02019-12-06 07:11:35 -08001106 public <T extends Info> T getPrerequisite(
dslomovde965ac2017-07-31 21:07:51 +02001107 String attributeName, Mode mode, final NativeProvider<T> skylarkKey) {
Sergio Campamae8cecd92016-12-13 18:49:28 +00001108 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
1109 return prerequisite == null ? null : prerequisite.get(skylarkKey);
1110 }
1111
1112 /**
cparsonsabeb8512018-06-11 12:44:06 -07001113 * Returns the declared provider (native and Skylark) for the specified constructor under the
1114 * specified attribute of this target in the BUILD file. May return null if there is no
1115 * TransitiveInfoCollection under the specified attribute.
1116 */
1117 @Nullable
adonovana11e2d02019-12-06 07:11:35 -08001118 public <T extends Info> T getPrerequisite(
cparsonsabeb8512018-06-11 12:44:06 -07001119 String attributeName, Mode mode, final BuiltinProvider<T> skylarkKey) {
1120 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
1121 return prerequisite == null ? null : prerequisite.get(skylarkKey);
1122 }
1123
1124
1125 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001126 * Returns all the providers of the specified type that are listed under the specified attribute
1127 * of this target in the BUILD file, and that contain the specified provider.
1128 */
1129 public <C extends TransitiveInfoProvider> Iterable<? extends TransitiveInfoCollection>
1130 getPrerequisitesIf(String attributeName, Mode mode, final Class<C> classType) {
1131 AnalysisUtils.checkProvider(classType);
1132 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
1133 }
1134
1135 /**
dslomov73527c32017-07-27 17:35:46 +02001136 * Returns all the providers of the specified type that are listed under the specified attribute
1137 * of this target in the BUILD file, and that contain the specified provider.
1138 */
dslomovde965ac2017-07-31 21:07:51 +02001139 public <C extends Info> Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
1140 String attributeName, Mode mode, final NativeProvider<C> classType) {
dslomov73527c32017-07-27 17:35:46 +02001141 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
1142 }
1143
dslomov73527c32017-07-27 17:35:46 +02001144 /**
Googler7ac77232019-06-04 14:26:47 -07001145 * Returns all the providers of the specified type that are listed under the specified attribute
1146 * of this target in the BUILD file, and that contain the specified provider.
1147 */
1148 public <C extends Info> Iterable<? extends TransitiveInfoCollection> getPrerequisitesIf(
1149 String attributeName, Mode mode, final BuiltinProvider<C> classType) {
1150 return AnalysisUtils.filterByProvider(getPrerequisites(attributeName, mode), classType);
1151 }
1152
1153 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001154 * Returns the prerequisite referred to by the specified attribute. Also checks whether
1155 * the attribute is marked as executable and that the target referred to can actually be
1156 * executed.
1157 *
1158 * <p>The {@code mode} argument must match the configuration transition specified in the
1159 * definition of the attribute.
1160 *
1161 * @param attributeName the name of the attribute
1162 * @param mode the configuration transition of the attribute
1163 *
1164 * @return the {@link FilesToRunProvider} interface of the prerequisite.
1165 */
Carmi Grushko802f39e2016-04-06 20:03:56 +00001166 @Nullable
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001167 public FilesToRunProvider getExecutablePrerequisite(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +00001168 Attribute ruleDefinition = attributes().getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001169
1170 if (ruleDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001171 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001172 + " is not defined");
1173 }
1174 if (!ruleDefinition.isExecutable()) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001175 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001176 + " is not configured to be executable");
1177 }
1178
1179 TransitiveInfoCollection prerequisite = getPrerequisite(attributeName, mode);
1180 if (prerequisite == null) {
1181 return null;
1182 }
1183
1184 FilesToRunProvider result = prerequisite.getProvider(FilesToRunProvider.class);
1185 if (result == null || result.getExecutable() == null) {
1186 attributeError(
1187 attributeName, prerequisite.getLabel() + " does not refer to a valid executable target");
1188 }
1189 return result;
1190 }
1191
ulfjack08ff9b82017-09-28 04:08:06 -04001192 public void initConfigurationMakeVariableContext(
1193 Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
1194 Preconditions.checkState(configurationMakeVariableContext == null);
1195 configurationMakeVariableContext =
1196 new ConfigurationMakeVariableContext(
1197 this, getRule().getPackage(), getConfiguration(), makeVariableSuppliers);
1198 }
1199
1200 public void initConfigurationMakeVariableContext(MakeVariableSupplier... makeVariableSuppliers) {
1201 initConfigurationMakeVariableContext(ImmutableList.copyOf(makeVariableSuppliers));
1202 }
1203
ulfjack01bf32e2017-11-02 17:50:07 -04001204 public Expander getExpander(TemplateContext templateContext) {
1205 return new Expander(this, templateContext);
Liam Miller-Cushonce6a7b22016-02-03 18:12:36 +00001206 }
1207
ulfjack07860132017-09-29 08:59:44 -04001208 public Expander getExpander() {
1209 return new Expander(this, getConfigurationMakeVariableContext());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001210 }
1211
Googlera45a8e02019-05-13 11:17:02 -07001212 public Expander getExpander(ImmutableMap<Label, ImmutableCollection<Artifact>> labelMap) {
1213 return new Expander(this, getConfigurationMakeVariableContext(), labelMap);
1214 }
1215
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001216 /**
ulfjack08ff9b82017-09-28 04:08:06 -04001217 * Returns a cached context that maps Make variable names (string) to values (string) without any
1218 * extra {@link MakeVariableSupplier}.
hlopkoa4778052017-05-26 11:37:28 +02001219 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001220 public ConfigurationMakeVariableContext getConfigurationMakeVariableContext() {
1221 if (configurationMakeVariableContext == null) {
ulfjack08ff9b82017-09-28 04:08:06 -04001222 initConfigurationMakeVariableContext(ImmutableList.<MakeVariableSupplier>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001223 }
1224 return configurationMakeVariableContext;
1225 }
1226
juliexxiab5f9d742020-04-09 13:07:13 -07001227 // TODO(b/151742236): provide access to other non-default toolchain contexts.
John Cater13263f72017-05-24 19:06:47 +02001228 @Nullable
John Catercdfa9ca2019-04-05 12:32:09 -07001229 public ResolvedToolchainContext getToolchainContext() {
juliexxiab5f9d742020-04-09 13:07:13 -07001230 return toolchainContexts == null ? null : toolchainContexts.getDefaultToolchainContext();
1231 }
1232
1233 @Nullable
1234 public ToolchainCollection<ResolvedToolchainContext> getToolchainContextsForTesting() {
1235 return toolchainContexts;
John Catereca28402017-05-17 21:44:12 +02001236 }
1237
jcater0a1e9eb2019-12-17 09:58:38 -08001238 public boolean targetPlatformHasConstraint(ConstraintValueInfo constraintValue) {
juliexxiab5f9d742020-04-09 13:07:13 -07001239 if (toolchainContexts == null
1240 || toolchainContexts.getDefaultToolchainContext().targetPlatform() == null) {
jcater0a1e9eb2019-12-17 09:58:38 -08001241 return false;
1242 }
juliexxiab5f9d742020-04-09 13:07:13 -07001243 // All toolchain contexts should have the same target platform so we access via the default.
1244 return toolchainContexts
1245 .getDefaultToolchainContext()
1246 .targetPlatform()
1247 .constraints()
1248 .hasConstraintValue(constraintValue);
jcater0a1e9eb2019-12-17 09:58:38 -08001249 }
1250
gregce6acfe4e2018-05-25 08:38:39 -07001251 public ConstraintSemantics getConstraintSemantics() {
1252 return constraintSemantics;
1253 }
1254
gregce966dc232019-10-18 15:34:07 -07001255 public ImmutableSet<String> getRequiredConfigFragments() {
1256 return requiredConfigFragments;
1257 }
1258
Googlerb5082462019-08-26 14:28:09 -07001259 public Map<String, String> getTargetExecProperties() {
1260 if (isAttrDefined(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT)) {
1261 return attributes.get(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT);
1262 } else {
1263 return ImmutableMap.of();
1264 }
1265 }
1266
John Cater15c90b32017-12-18 08:34:40 -08001267 @Override
1268 @Nullable
1269 public PlatformInfo getExecutionPlatform() {
1270 if (getToolchainContext() == null) {
1271 return null;
1272 }
John Caterc8bd74f2018-06-22 14:20:22 -07001273 return getToolchainContext().executionPlatform();
John Cater15c90b32017-12-18 08:34:40 -08001274 }
1275
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001276 private void checkAttribute(String attributeName, Mode mode) {
Greg Estren7f534232016-12-01 21:38:25 +00001277 Attribute attributeDefinition = attributes.getAttributeDefinition(attributeName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001278 if (attributeDefinition == null) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001279 throw new IllegalStateException(getRule().getLocation() + ": " + getRuleClassNameForLogging()
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001280 + " attribute " + attributeName + " is not defined");
1281 }
Michael Staiba751f922017-02-14 15:50:04 +00001282 if (attributeDefinition.getType().getLabelClass() != LabelClass.DEPENDENCY) {
Michael Staib8824d5e2016-01-20 21:37:05 +00001283 throw new IllegalStateException(getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001284 + " is not a label type attribute");
1285 }
John Cater2c0dece2019-04-02 09:18:18 -07001286 TransitionFactory<AttributeTransitionData> transitionFactory =
John Cater5adcd3e2019-03-28 10:14:32 -07001287 attributeDefinition.getTransitionFactory();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001288 if (mode == Mode.HOST) {
John Cater5adcd3e2019-03-28 10:14:32 -07001289 if (transitionFactory.isSplit()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001290 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001291 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001292 + " is not configured for the host configuration");
1293 }
1294 } else if (mode == Mode.TARGET) {
John Cater5adcd3e2019-03-28 10:14:32 -07001295 if (transitionFactory.isSplit() && !NoTransition.isInstance(transitionFactory)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001296 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001297 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001298 + " is not configured for the target configuration");
1299 }
1300 } else if (mode == Mode.DATA) {
gregce475d91a2018-05-25 12:18:27 -07001301 throw new IllegalStateException(getRule().getLocation() + ": "
1302 + getRuleClassNameForLogging() + " attribute " + attributeName
1303 + ": DATA transition no longer supported"); // See b/80157700.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001304 } else if (mode == Mode.SPLIT) {
jcatere8f5a982019-04-02 11:12:19 -07001305 if (!(attributeDefinition.getTransitionFactory().isSplit())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001306 throw new IllegalStateException(getRule().getLocation() + ": "
Michael Staib8824d5e2016-01-20 21:37:05 +00001307 + getRuleClassNameForLogging() + " attribute " + attributeName
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001308 + " is not configured for a split transition");
1309 }
1310 }
1311 }
1312
1313 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001314 * For the specified attribute "attributeName" (which must be of type
1315 * list(label)), resolve all the labels into ConfiguredTargets (for the
1316 * configuration appropriate to the attribute) and return their build
1317 * artifacts as a {@link PrerequisiteArtifacts} instance.
1318 *
1319 * @param attributeName the name of the attribute to traverse
1320 */
1321 public PrerequisiteArtifacts getPrerequisiteArtifacts(String attributeName, Mode mode) {
1322 return PrerequisiteArtifacts.get(this, attributeName, mode);
1323 }
1324
1325 /**
1326 * For the specified attribute "attributeName" (which must be of type label),
1327 * resolves the ConfiguredTarget and returns its single build artifact.
1328 *
1329 * <p>If the attribute is optional, has no default and was not specified, then
1330 * null will be returned. Note also that null is returned (and an attribute
1331 * error is raised) if there wasn't exactly one build artifact for the target.
1332 */
1333 public Artifact getPrerequisiteArtifact(String attributeName, Mode mode) {
1334 TransitiveInfoCollection target = getPrerequisite(attributeName, mode);
1335 return transitiveInfoCollectionToArtifact(attributeName, target);
1336 }
1337
1338 /**
1339 * Equivalent to getPrerequisiteArtifact(), but also asserts that
1340 * host-configuration is appropriate for the specified attribute.
1341 */
1342 public Artifact getHostPrerequisiteArtifact(String attributeName) {
1343 TransitiveInfoCollection target = getPrerequisite(attributeName, Mode.HOST);
1344 return transitiveInfoCollectionToArtifact(attributeName, target);
1345 }
1346
1347 private Artifact transitiveInfoCollectionToArtifact(
1348 String attributeName, TransitiveInfoCollection target) {
1349 if (target != null) {
ulfjack8d8f62f2019-12-05 15:03:53 -08001350 NestedSet<Artifact> artifacts = target.getProvider(FileProvider.class).getFilesToBuild();
1351 if (artifacts.isSingleton()) {
1352 return artifacts.getSingleton();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001353 } else {
1354 attributeError(attributeName, target.getLabel() + " expected a single artifact");
1355 }
1356 }
1357 return null;
1358 }
1359
1360 /**
1361 * Returns the sole file in the "srcs" attribute. Reports an error and
1362 * (possibly) returns null if "srcs" does not identify a single file of the
1363 * expected type.
1364 */
1365 public Artifact getSingleSource(String fileTypeName) {
1366 List<Artifact> srcs = PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list();
1367 switch (srcs.size()) {
1368 case 0 : // error already issued by getSrc()
1369 return null;
1370 case 1 : // ok
1371 return Iterables.getOnlyElement(srcs);
1372 default :
1373 attributeError("srcs", "only a single " + fileTypeName + " is allowed here");
1374 return srcs.get(0);
1375 }
1376 }
1377
1378 public Artifact getSingleSource() {
Michael Staib8824d5e2016-01-20 21:37:05 +00001379 return getSingleSource(getRuleClassNameForLogging() + " source file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001380 }
1381
1382 /**
1383 * Returns a path fragment qualified by the rule name and unique fragment to
1384 * disambiguate artifacts produced from the source file appearing in
1385 * multiple rules.
1386 *
1387 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1388 */
1389 public final PathFragment getUniqueDirectory(String fragment) {
nharmata5e924af2017-05-02 18:16:23 +02001390 return getUniqueDirectory(PathFragment.create(fragment));
1391 }
1392
1393 /**
1394 * Returns a path fragment qualified by the rule name and unique fragment to
1395 * disambiguate artifacts produced from the source file appearing in
1396 * multiple rules.
1397 *
1398 * <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
1399 */
1400 public final PathFragment getUniqueDirectory(PathFragment fragment) {
1401 return AnalysisUtils.getUniqueDirectory(getLabel(), fragment);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001402 }
1403
1404 /**
1405 * Check that all targets that were specified as sources are from the same
1406 * package as this rule. Output a warning or an error for every target that is
1407 * imported from a different package.
1408 */
1409 public void checkSrcsSamePackage(boolean onlyWarn) {
1410 PathFragment packageName = getLabel().getPackageFragment();
1411 for (Artifact srcItem : PrerequisiteArtifacts.get(this, "srcs", Mode.TARGET).list()) {
1412 if (!srcItem.isSourceArtifact()) {
1413 // In theory, we should not do this check. However, in practice, we
1414 // have a couple of rules that do not obey the "srcs must contain
1415 // files and only files" rule. Thus, we are stuck with this hack here :(
1416 continue;
1417 }
1418 Label associatedLabel = srcItem.getOwner();
1419 PathFragment itemPackageName = associatedLabel.getPackageFragment();
1420 if (!itemPackageName.equals(packageName)) {
1421 String message = "please do not import '" + associatedLabel + "' directly. "
1422 + "You should either move the file to this package or depend on "
1423 + "an appropriate rule there";
1424 if (onlyWarn) {
1425 attributeWarning("srcs", message);
1426 } else {
1427 attributeError("srcs", message);
1428 }
1429 }
1430 }
1431 }
1432
1433
1434 /**
1435 * Returns the label to which the {@code NODEP_LABEL} attribute
1436 * {@code attrName} refers, checking that it is a valid label, and that it is
1437 * referring to a local target. Reports a warning otherwise.
1438 */
1439 public Label getLocalNodepLabelAttribute(String attrName) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001440 Label label = attributes().get(attrName, BuildType.NODEP_LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001441 if (label == null) {
1442 return null;
1443 }
1444
1445 if (!getTarget().getLabel().getPackageFragment().equals(label.getPackageFragment())) {
1446 attributeWarning(attrName, "does not reference a local rule");
1447 }
1448
1449 return label;
1450 }
1451
asteinb0de45462018-05-17 08:07:12 -07001452 @Override
Florian Weikert4b67d4f2015-09-14 13:35:34 +00001453 public Artifact getImplicitOutputArtifact(ImplicitOutputsFunction function)
1454 throws InterruptedException {
gregce11f3b0e2019-06-07 17:12:06 -07001455 return getImplicitOutputArtifact(function, /*contentBasedPath=*/ false);
1456 }
1457
1458 /**
1459 * Same as {@link #getImplicitOutputArtifact(ImplicitOutputsFunction)} but includes the option to
1460 * use a content-based path for this artifact (see {@link
1461 * BuildConfiguration#useContentBasedOutputPaths()}).
1462 */
1463 public Artifact getImplicitOutputArtifact(
1464 ImplicitOutputsFunction function, boolean contentBasedPath) throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001465 Iterable<String> result;
1466 try {
vladmos076977e2017-12-02 14:15:32 -08001467 result =
1468 function.getImplicitOutputs(
1469 getAnalysisEnvironment().getEventHandler(), RawAttributeMapper.of(rule));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001470 } catch (EvalException e) {
1471 // It's ok as long as we don't use this method from Skylark.
1472 throw new IllegalStateException(e);
1473 }
gregce11f3b0e2019-06-07 17:12:06 -07001474 return getImplicitOutputArtifact(Iterables.getOnlyElement(result), contentBasedPath);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001475 }
1476
1477 /**
1478 * Only use from Skylark. Returns the implicit output artifact for a given output path.
1479 */
1480 public Artifact getImplicitOutputArtifact(String path) {
gregce11f3b0e2019-06-07 17:12:06 -07001481 return getImplicitOutputArtifact(path, /*contentBasedPath=*/ false);
1482 }
1483
1484 /**
1485 * Same as {@link #getImplicitOutputArtifact(String)} but includes the option to use a a
1486 * content-based path for this artifact (see {@link
1487 * BuildConfiguration#useContentBasedOutputPaths()}).
1488 */
1489 private Artifact getImplicitOutputArtifact(String path, boolean contentBasedPath) {
1490 return getPackageRelativeArtifact(path, getBinOrGenfilesDirectory(), contentBasedPath);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001491 }
1492
1493 /**
1494 * Convenience method to return a host configured target for the "compiler"
1495 * attribute. Allows caller to decide whether a warning should be printed if
1496 * the "compiler" attribute is not set to the default value.
1497 *
1498 * @param warnIfNotDefault if true, print a warning if the value for the
1499 * "compiler" attribute is set to something other than the default
1500 * @return a ConfiguredTarget using the host configuration for the "compiler"
1501 * attribute
1502 */
1503 public final FilesToRunProvider getCompiler(boolean warnIfNotDefault) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001504 Label label = attributes().get("compiler", BuildType.LABEL);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001505 if (warnIfNotDefault && !label.equals(getRule().getAttrDefaultValue("compiler"))) {
1506 attributeWarning("compiler", "setting the compiler is strongly discouraged");
1507 }
1508 return getExecutablePrerequisite("compiler", Mode.HOST);
1509 }
1510
1511 /**
1512 * Returns the (unmodifiable, ordered) list of artifacts which are the outputs
1513 * of this target.
1514 *
1515 * <p>Each element in this list is associated with a single output, either
1516 * declared implicitly (via setImplicitOutputsFunction()) or explicitly
1517 * (listed in the 'outs' attribute of our rule).
1518 */
1519 public final ImmutableList<Artifact> getOutputArtifacts() {
1520 ImmutableList.Builder<Artifact> artifacts = ImmutableList.builder();
1521 for (OutputFile out : getRule().getOutputFiles()) {
1522 artifacts.add(createOutputArtifact(out));
1523 }
1524 return artifacts.build();
1525 }
1526
1527 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001528 * Like {@link #getOutputArtifacts()} but for a singular output item.
1529 * Reports an error if the "out" attribute is not a singleton.
1530 *
1531 * @return null if the output list is empty, the artifact for the first item
1532 * of the output list otherwise
1533 */
1534 public Artifact getOutputArtifact() {
1535 List<Artifact> outs = getOutputArtifacts();
1536 if (outs.size() != 1) {
1537 attributeError("out", "exactly one output file required");
1538 if (outs.isEmpty()) {
1539 return null;
1540 }
1541 }
1542 return outs.get(0);
1543 }
1544
plf727a07d2019-02-01 02:27:35 -08001545 @Override
janakr658d47f2019-05-29 11:11:30 -07001546 public final Artifact.DerivedArtifact getRelatedArtifact(
1547 PathFragment pathFragment, String extension) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001548 PathFragment file = FileSystemUtils.replaceExtension(pathFragment, extension);
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +00001549 return getDerivedArtifact(file, getConfiguration().getBinDirectory(rule.getRepository()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001550 }
1551
1552 /**
Googlerf812a2f2016-06-13 16:14:10 +00001553 * Returns true if the target for this context is a test target.
1554 */
1555 public boolean isTestTarget() {
1556 return TargetUtils.isTestRule(getTarget());
1557 }
1558
Googlercfdeb4d2018-02-08 07:13:33 -08001559 /** Returns true if the testonly attribute is set on this context. */
1560 public boolean isTestOnlyTarget() {
1561 return attributes().has("testonly", Type.BOOLEAN) && attributes().get("testonly", Type.BOOLEAN);
1562 }
1563
Googlerf812a2f2016-06-13 16:14:10 +00001564 /**
Klaus Aehliga85af942019-10-29 07:48:32 -07001565 * Returns true if {@code label} is visible from {@code prerequisite}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001566 *
1567 * <p>This only computes the logic as implemented by the visibility system. The final decision
jcater0de10972020-04-07 12:15:05 -07001568 * whether a dependency is allowed is made by {@link PrerequisiteValidator}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001569 */
Klaus Aehliga85af942019-10-29 07:48:32 -07001570 public static boolean isVisible(Label label, TransitiveInfoCollection prerequisite) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001571 // Check visibility attribute
cushon34ff85e2017-11-15 08:59:27 -08001572 for (PackageGroupContents specification :
Ulf Adamscd31d3b2019-12-16 00:50:03 -08001573 prerequisite.getProvider(VisibilityProvider.class).getVisibility().toList()) {
Klaus Aehliga85af942019-10-29 07:48:32 -07001574 if (specification.containsPackage(label.getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001575 return true;
1576 }
1577 }
1578
1579 return false;
1580 }
1581
1582 /**
Klaus Aehliga85af942019-10-29 07:48:32 -07001583 * Returns true if {@code rule} is visible from {@code prerequisite}.
1584 *
1585 * <p>This only computes the logic as implemented by the visibility system. The final decision
jcater0de10972020-04-07 12:15:05 -07001586 * whether a dependency is allowed is made by {@link PrerequisiteValidator}.
Klaus Aehliga85af942019-10-29 07:48:32 -07001587 */
1588 public static boolean isVisible(Rule rule, TransitiveInfoCollection prerequisite) {
1589 return isVisible(rule.getLabel(), prerequisite);
1590 }
1591
dchai40f464c2019-11-29 02:23:06 -08001592 /** @return the set of features applicable for the current rule. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001593 public ImmutableSet<String> getFeatures() {
Googler993f1de2018-02-20 02:31:10 -08001594 return enabledFeatures;
1595 }
1596
dchai40f464c2019-11-29 02:23:06 -08001597 /** @return the set of features that are disabled for the current rule. */
Googler993f1de2018-02-20 02:31:10 -08001598 public ImmutableSet<String> getDisabledFeatures() {
1599 return disabledFeatures;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001600 }
1601
Florian Weikertb8a6a942015-09-25 12:36:08 +00001602 @Override
plf43109892019-02-12 05:45:05 -08001603 public RuleErrorConsumer getRuleErrorConsumer() {
1604 return this;
1605 }
1606
1607 @Override
Florian Weikertb8a6a942015-09-25 12:36:08 +00001608 public String toString() {
1609 return "RuleContext(" + getLabel() + ", " + getConfiguration() + ")";
1610 }
1611
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001612 /**
1613 * Builder class for a RuleContext.
1614 */
Florian Weikertb8a6a942015-09-25 12:36:08 +00001615 public static final class Builder implements RuleErrorConsumer {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001616 private final AnalysisEnvironment env;
lpino5fe7ed02018-07-18 05:55:23 -07001617 private final Target target;
Michael Staibb51251e2015-09-29 23:31:51 +00001618 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
lberki78651d42018-04-06 01:52:58 -07001619 private ImmutableList<Class<? extends BuildConfiguration.Fragment>> universalFragments;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001620 private final BuildConfiguration configuration;
Greg Estren9eb1cf02015-06-26 22:18:35 +00001621 private final BuildConfiguration hostConfiguration;
janakreaff19c2019-01-31 13:59:40 -08001622 private final ActionLookupValue.ActionLookupKey actionOwnerSymbol;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001623 private final PrerequisiteValidator prerequisiteValidator;
cparsonse8d450c2018-10-04 16:01:53 -07001624 private final RuleErrorConsumer reporter;
janakr9c101402018-03-10 06:48:59 -08001625 private OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap;
Lukacs Berki7894c182016-05-10 12:07:01 +00001626 private ImmutableMap<Label, ConfigMatchingProvider> configConditions;
cushon34ff85e2017-11-15 08:59:27 -08001627 private NestedSet<PackageGroupContents> visibility;
Dmitry Lomovace678e2015-12-16 15:10:20 +00001628 private ImmutableMap<String, Attribute> aspectAttributes;
dslomov44d15712017-12-20 05:42:28 -08001629 private ImmutableList<Aspect> aspects;
juliexxiab5f9d742020-04-09 13:07:13 -07001630 private ToolchainCollection<ResolvedToolchainContext> toolchainContexts;
gregce6acfe4e2018-05-25 08:38:39 -07001631 private ConstraintSemantics constraintSemantics;
gregce966dc232019-10-18 15:34:07 -07001632 private ImmutableSet<String> requiredConfigFragments = ImmutableSet.of();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001633
ulfjack865b6212018-06-14 03:41:55 -07001634 @VisibleForTesting
1635 public Builder(
Michael Staib8824d5e2016-01-20 21:37:05 +00001636 AnalysisEnvironment env,
lpino5fe7ed02018-07-18 05:55:23 -07001637 Target target,
dslomov44d15712017-12-20 05:42:28 -08001638 ImmutableList<Aspect> aspects,
Michael Staib8824d5e2016-01-20 21:37:05 +00001639 BuildConfiguration configuration,
Greg Estren9eb1cf02015-06-26 22:18:35 +00001640 BuildConfiguration hostConfiguration,
Michael Staib8824d5e2016-01-20 21:37:05 +00001641 PrerequisiteValidator prerequisiteValidator,
janakreaff19c2019-01-31 13:59:40 -08001642 ConfigurationFragmentPolicy configurationFragmentPolicy,
1643 ActionLookupValue.ActionLookupKey actionOwnerSymbol) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001644 this.env = Preconditions.checkNotNull(env);
lpino5fe7ed02018-07-18 05:55:23 -07001645 this.target = Preconditions.checkNotNull(target);
dslomov44d15712017-12-20 05:42:28 -08001646 this.aspects = aspects;
Michael Staib8824d5e2016-01-20 21:37:05 +00001647 this.configurationFragmentPolicy = Preconditions.checkNotNull(configurationFragmentPolicy);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001648 this.configuration = Preconditions.checkNotNull(configuration);
Greg Estren9eb1cf02015-06-26 22:18:35 +00001649 this.hostConfiguration = Preconditions.checkNotNull(hostConfiguration);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001650 this.prerequisiteValidator = prerequisiteValidator;
janakreaff19c2019-01-31 13:59:40 -08001651 this.actionOwnerSymbol = Preconditions.checkNotNull(actionOwnerSymbol);
cparsonse8d450c2018-10-04 16:01:53 -07001652 if (configuration.allowAnalysisFailures()) {
1653 reporter = new SuppressingErrorReporter();
1654 } else {
ulfjack07917642019-09-12 02:09:36 -07001655 reporter =
1656 new ErrorReporter(
1657 env, target.getAssociatedRule(), configuration, getRuleClassNameForLogging());
cparsonse8d450c2018-10-04 16:01:53 -07001658 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001659 }
1660
ulfjack865b6212018-06-14 03:41:55 -07001661 @VisibleForTesting
1662 public RuleContext build() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001663 Preconditions.checkNotNull(prerequisiteMap);
1664 Preconditions.checkNotNull(configConditions);
1665 Preconditions.checkNotNull(visibility);
gregce6acfe4e2018-05-25 08:38:39 -07001666 Preconditions.checkNotNull(constraintSemantics);
lpino5fe7ed02018-07-18 05:55:23 -07001667 AttributeMap attributes =
1668 ConfiguredAttributeMapper.of(target.getAssociatedRule(), configConditions);
Nathan Harmatafcb17112016-04-13 16:56:58 +00001669 validateAttributes(attributes);
janakr9c101402018-03-10 06:48:59 -08001670 ListMultimap<String, ConfiguredTargetAndData> targetMap = createTargetMap();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001671 ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap =
lpino5fe7ed02018-07-18 05:55:23 -07001672 createFilesetEntryMap(target.getAssociatedRule(), configConditions);
Michael Staib8824d5e2016-01-20 21:37:05 +00001673 return new RuleContext(
1674 this,
Nathan Harmatafcb17112016-04-13 16:56:58 +00001675 attributes,
Michael Staib8824d5e2016-01-20 21:37:05 +00001676 targetMap,
1677 filesetEntryMap,
1678 configConditions,
lberki78651d42018-04-06 01:52:58 -07001679 universalFragments,
Michael Staib8824d5e2016-01-20 21:37:05 +00001680 getRuleClassNameForLogging(),
janakreaff19c2019-01-31 13:59:40 -08001681 actionOwnerSymbol,
John Cater13263f72017-05-24 19:06:47 +02001682 aspectAttributes != null ? aspectAttributes : ImmutableMap.<String, Attribute>of(),
juliexxiab5f9d742020-04-09 13:07:13 -07001683 toolchainContexts,
gregce966dc232019-10-18 15:34:07 -07001684 constraintSemantics,
1685 requiredConfigFragments);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001686 }
1687
Nathan Harmatafcb17112016-04-13 16:56:58 +00001688 private void validateAttributes(AttributeMap attributes) {
lpino5fe7ed02018-07-18 05:55:23 -07001689 target
1690 .getAssociatedRule()
1691 .getRuleClassObject()
michajloc1062a42018-09-26 14:53:38 -07001692 .checkAttributesNonEmpty(reporter, attributes);
Nathan Harmatafcb17112016-04-13 16:56:58 +00001693 }
1694
ulfjack865b6212018-06-14 03:41:55 -07001695 public Builder setVisibility(NestedSet<PackageGroupContents> visibility) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001696 this.visibility = visibility;
1697 return this;
1698 }
1699
1700 /**
1701 * Sets the prerequisites and checks their visibility. It also generates appropriate error or
1702 * warning messages and sets the error flag as appropriate.
1703 */
ulfjack865b6212018-06-14 03:41:55 -07001704 public Builder setPrerequisites(
janakr9c101402018-03-10 06:48:59 -08001705 OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001706 this.prerequisiteMap = Preconditions.checkNotNull(prerequisiteMap);
1707 return this;
1708 }
1709
1710 /**
Carmi Grushko06f65f72015-11-02 22:42:24 +00001711 * Adds attributes which are defined by an Aspect (and not by RuleClass).
1712 */
ulfjack865b6212018-06-14 03:41:55 -07001713 public Builder setAspectAttributes(Map<String, Attribute> aspectAttributes) {
Dmitry Lomovace678e2015-12-16 15:10:20 +00001714 this.aspectAttributes = ImmutableMap.copyOf(aspectAttributes);
Carmi Grushko06f65f72015-11-02 22:42:24 +00001715 return this;
1716 }
1717
1718 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001719 * Sets the configuration conditions needed to determine which paths to follow for this
1720 * rule's configurable attributes.
1721 */
ulfjack865b6212018-06-14 03:41:55 -07001722 public Builder setConfigConditions(
1723 ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001724 this.configConditions = Preconditions.checkNotNull(configConditions);
1725 return this;
1726 }
1727
Greg Estrenc5a352f2015-11-13 17:25:36 +00001728 /**
1729 * Sets the fragment that can be legally accessed even when not explicitly declared.
1730 */
ulfjack865b6212018-06-14 03:41:55 -07001731 public Builder setUniversalFragments(
lberki78651d42018-04-06 01:52:58 -07001732 ImmutableList<Class<? extends BuildConfiguration.Fragment>> fragments) {
Greg Estrenc5a352f2015-11-13 17:25:36 +00001733 // TODO(bazel-team): Add this directly to ConfigurationFragmentPolicy, so we
1734 // don't need separate logic specifically for checking this fragment. The challenge is
1735 // that we need RuleClassProvider to figure out what this fragment is, and not every
1736 // call state that creates ConfigurationFragmentPolicy has access to that.
lberki78651d42018-04-06 01:52:58 -07001737 this.universalFragments = fragments;
Greg Estrenc5a352f2015-11-13 17:25:36 +00001738 return this;
1739 }
1740
John Catercdfa9ca2019-04-05 12:32:09 -07001741 /** Sets the {@link ResolvedToolchainContext} used to access toolchains used by this rule. */
1742 public Builder setToolchainContext(ResolvedToolchainContext toolchainContext) {
juliexxiab5f9d742020-04-09 13:07:13 -07001743 Preconditions.checkState(
1744 this.toolchainContexts == null,
1745 "toolchainContexts has already been set for this Builder");
1746 this.toolchainContexts =
1747 new ToolchainCollection.Builder<ResolvedToolchainContext>()
1748 .addDefaultContext(toolchainContext)
1749 .build();
1750 return this;
1751 }
1752
1753 /** Sets the collection of {@link ResolvedToolchainContext}s available to this rule. */
1754 @VisibleForTesting
1755 public Builder setToolchainContexts(
1756 ToolchainCollection<ResolvedToolchainContext> toolchainContexts) {
1757 Preconditions.checkState(
1758 this.toolchainContexts == null,
1759 "toolchainContexts has already been set for this Builder");
1760 this.toolchainContexts = toolchainContexts;
John Cater13263f72017-05-24 19:06:47 +02001761 return this;
1762 }
1763
ulfjack865b6212018-06-14 03:41:55 -07001764 public Builder setConstraintSemantics(ConstraintSemantics constraintSemantics) {
gregce6acfe4e2018-05-25 08:38:39 -07001765 this.constraintSemantics = constraintSemantics;
1766 return this;
1767 }
1768
gregce966dc232019-10-18 15:34:07 -07001769 public Builder setRequiredConfigFragments(ImmutableSet<String> requiredConfigFragments) {
1770 this.requiredConfigFragments = requiredConfigFragments;
1771 return this;
1772 }
1773
janakr9c101402018-03-10 06:48:59 -08001774 private boolean validateFilesetEntry(FilesetEntry filesetEntry, ConfiguredTargetAndData src) {
felly2b3befd2018-08-10 10:37:56 -07001775 NestedSet<Artifact> filesToBuild =
1776 src.getConfiguredTarget().getProvider(FileProvider.class).getFilesToBuild();
ulfjack8d8f62f2019-12-05 15:03:53 -08001777 if (filesToBuild.isSingleton() && filesToBuild.getSingleton().isFileset()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001778 return true;
1779 }
felly2b3befd2018-08-10 10:37:56 -07001780
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001781 if (filesetEntry.isSourceFileset()) {
1782 return true;
1783 }
1784
1785 Target srcTarget = src.getTarget();
1786 if (!(srcTarget instanceof FileTarget)) {
1787 attributeError("entries", String.format(
1788 "Invalid 'srcdir' target '%s'. Must be another Fileset or package",
1789 srcTarget.getLabel()));
1790 return false;
1791 }
1792
1793 if (srcTarget instanceof OutputFile) {
1794 attributeWarning("entries", String.format("'srcdir' target '%s' is not an input file. "
1795 + "This forces the Fileset to be executed unconditionally",
1796 srcTarget.getLabel()));
1797 }
1798
1799 return true;
1800 }
1801
1802 /**
1803 * Determines and returns a map from attribute name to list of configured fileset entries, based
1804 * on a PrerequisiteMap instance.
1805 */
1806 private ListMultimap<String, ConfiguredFilesetEntry> createFilesetEntryMap(
Lukacs Berki7894c182016-05-10 12:07:01 +00001807 final Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
lpino5fe7ed02018-07-18 05:55:23 -07001808 if (!target.getTargetKind().equals("Fileset rule")) {
1809 return ImmutableSortedKeyListMultimap.<String, ConfiguredFilesetEntry>builder().build();
1810 }
1811
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001812 final ImmutableSortedKeyListMultimap.Builder<String, ConfiguredFilesetEntry> mapBuilder =
1813 ImmutableSortedKeyListMultimap.builder();
1814 for (Attribute attr : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001815 if (attr.getType() != BuildType.FILESET_ENTRY_LIST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001816 continue;
1817 }
1818 String attributeName = attr.getName();
janakr9c101402018-03-10 06:48:59 -08001819 Map<Label, ConfiguredTargetAndData> ctMap = new HashMap<>();
1820 for (ConfiguredTargetAndData prerequisite : prerequisiteMap.get(attr)) {
janakrf3e6f252018-01-18 07:45:12 -08001821 ctMap.put(
1822 AliasProvider.getDependencyLabel(prerequisite.getConfiguredTarget()), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001823 }
1824 List<FilesetEntry> entries = ConfiguredAttributeMapper.of(rule, configConditions)
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001825 .get(attributeName, BuildType.FILESET_ENTRY_LIST);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001826 for (FilesetEntry entry : entries) {
1827 if (entry.getFiles() == null) {
1828 Label label = entry.getSrcLabel();
janakr9c101402018-03-10 06:48:59 -08001829 ConfiguredTargetAndData src = ctMap.get(label);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001830 if (!validateFilesetEntry(entry, src)) {
1831 continue;
1832 }
1833
janakrf3e6f252018-01-18 07:45:12 -08001834 mapBuilder.put(
1835 attributeName, new ConfiguredFilesetEntry(entry, src.getConfiguredTarget()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001836 } else {
1837 ImmutableList.Builder<TransitiveInfoCollection> files = ImmutableList.builder();
1838 for (Label file : entry.getFiles()) {
janakrf3e6f252018-01-18 07:45:12 -08001839 files.add(ctMap.get(file).getConfiguredTarget());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001840 }
1841 mapBuilder.put(attributeName, new ConfiguredFilesetEntry(entry, files.build()));
1842 }
1843 }
1844 }
1845 return mapBuilder.build();
1846 }
1847
janakrf3e6f252018-01-18 07:45:12 -08001848 /** Determines and returns a map from attribute name to list of configured targets. */
janakr9c101402018-03-10 06:48:59 -08001849 private ImmutableSortedKeyListMultimap<String, ConfiguredTargetAndData> createTargetMap() {
1850 ImmutableSortedKeyListMultimap.Builder<String, ConfiguredTargetAndData> mapBuilder =
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001851 ImmutableSortedKeyListMultimap.builder();
1852
janakr9c101402018-03-10 06:48:59 -08001853 for (Map.Entry<Attribute, Collection<ConfiguredTargetAndData>> entry :
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001854 prerequisiteMap.asMap().entrySet()) {
1855 Attribute attribute = entry.getKey();
1856 if (attribute == null) {
1857 continue;
1858 }
lberki1cd6d1e2017-06-14 16:20:19 +02001859
1860 if (attribute.isSingleArtifact() && entry.getValue().size() > 1) {
1861 attributeError(attribute.getName(), "must contain a single dependency");
1862 continue;
1863 }
1864
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001865 if (attribute.isSilentRuleClassFilter()) {
1866 Predicate<RuleClass> filter = attribute.getAllowedRuleClassesPredicate();
janakr9c101402018-03-10 06:48:59 -08001867 for (ConfiguredTargetAndData configuredTarget : entry.getValue()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001868 Target prerequisiteTarget = configuredTarget.getTarget();
1869 if ((prerequisiteTarget instanceof Rule)
1870 && filter.apply(((Rule) prerequisiteTarget).getRuleClassObject())) {
1871 validateDirectPrerequisite(attribute, configuredTarget);
1872 mapBuilder.put(attribute.getName(), configuredTarget);
1873 }
1874 }
1875 } else {
janakr9c101402018-03-10 06:48:59 -08001876 for (ConfiguredTargetAndData configuredTarget : entry.getValue()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001877 validateDirectPrerequisite(attribute, configuredTarget);
1878 mapBuilder.put(attribute.getName(), configuredTarget);
1879 }
1880 }
1881 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001882 return mapBuilder.build();
1883 }
1884
cparsons963881a2018-10-03 14:23:55 -07001885 /**
1886 * Post a raw event to the analysis environment's event handler. This circumvents normal
1887 * error and warning reporting functionality to post events, and should only be used
1888 * in rare cases where a custom event needs to be handled.
1889 */
Klaus Aehlig16a107d2017-05-31 18:02:43 +02001890 public void post(Postable event) {
cparsons963881a2018-10-03 14:23:55 -07001891 env.getEventHandler().post(event);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001892 }
1893
Florian Weikertb8a6a942015-09-25 12:36:08 +00001894 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001895 public void ruleError(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001896 reporter.ruleError(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001897 }
1898
Florian Weikertb8a6a942015-09-25 12:36:08 +00001899 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001900 public void attributeError(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001901 reporter.attributeError(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001902 }
1903
Florian Weikertb8a6a942015-09-25 12:36:08 +00001904 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001905 public void ruleWarning(String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001906 reporter.ruleWarning(message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001907 }
1908
Florian Weikertb8a6a942015-09-25 12:36:08 +00001909 @Override
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001910 public void attributeWarning(String attrName, String message) {
Florian Weikertb8a6a942015-09-25 12:36:08 +00001911 reporter.attributeWarning(attrName, message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001912 }
1913
cparsons0dcffc52017-10-13 23:40:31 +02001914 @Override
cparsons0dcffc52017-10-13 23:40:31 +02001915 public boolean hasErrors() {
1916 return reporter.hasErrors();
1917 }
1918
janakrf3e6f252018-01-18 07:45:12 -08001919 private String badPrerequisiteMessage(
lberkiee2dcae2018-03-28 05:49:04 -07001920 ConfiguredTargetAndData prerequisite, String reason, boolean isWarning) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001921 String msgReason = reason != null ? " (" + reason + ")" : "";
1922 if (isWarning) {
Googlere49cd592016-07-29 19:32:38 +00001923 return String.format(
lberkiee2dcae2018-03-28 05:49:04 -07001924 "%s is unexpected here%s; continuing anyway",
1925 AliasProvider.describeTargetWithAliases(prerequisite, TargetMode.WITH_KIND),
Googlere49cd592016-07-29 19:32:38 +00001926 msgReason);
1927 }
lberkiee2dcae2018-03-28 05:49:04 -07001928 return String.format("%s is misplaced here%s",
1929 AliasProvider.describeTargetWithAliases(prerequisite, TargetMode.WITH_KIND), msgReason);
Googlere49cd592016-07-29 19:32:38 +00001930 }
1931
janakrf3e6f252018-01-18 07:45:12 -08001932 private void reportBadPrerequisite(
1933 Attribute attribute,
janakr9c101402018-03-10 06:48:59 -08001934 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08001935 String reason,
1936 boolean isWarning) {
lberkiee2dcae2018-03-28 05:49:04 -07001937 String message = badPrerequisiteMessage(prerequisite, reason, isWarning);
Googlere49cd592016-07-29 19:32:38 +00001938 if (isWarning) {
1939 attributeWarning(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001940 } else {
Googlere49cd592016-07-29 19:32:38 +00001941 attributeError(attribute.getName(), message);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001942 }
1943 }
1944
janakrf3e6f252018-01-18 07:45:12 -08001945 private void validateDirectPrerequisiteType(
janakr9c101402018-03-10 06:48:59 -08001946 ConfiguredTargetAndData prerequisite, Attribute attribute) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001947 Target prerequisiteTarget = prerequisite.getTarget();
1948 Label prerequisiteLabel = prerequisiteTarget.getLabel();
1949
1950 if (prerequisiteTarget instanceof Rule) {
1951 Rule prerequisiteRule = (Rule) prerequisiteTarget;
1952
lpino5fe7ed02018-07-18 05:55:23 -07001953 String reason =
1954 attribute
1955 .getValidityPredicate()
1956 .checkValid(target.getAssociatedRule(), prerequisiteRule);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001957 if (reason != null) {
lberkiee2dcae2018-03-28 05:49:04 -07001958 reportBadPrerequisite(attribute, prerequisite, reason, false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001959 }
1960 }
1961
Yun Pengefd7ca12016-03-03 13:14:38 +00001962 if (prerequisiteTarget instanceof Rule) {
1963 validateRuleDependency(prerequisite, attribute);
1964 } else if (prerequisiteTarget instanceof FileTarget) {
1965 if (attribute.isStrictLabelCheckingEnabled()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001966 if (!attribute.getAllowedFileTypesPredicate()
1967 .apply(((FileTarget) prerequisiteTarget).getFilename())) {
1968 if (prerequisiteTarget instanceof InputFile
1969 && !((InputFile) prerequisiteTarget).getPath().exists()) {
1970 // Misplaced labels, no corresponding target exists
1971 if (attribute.getAllowedFileTypesPredicate().isNone()
1972 && !((InputFile) prerequisiteTarget).getFilename().contains(".")) {
1973 // There are no allowed files in the attribute but it's not a valid rule,
1974 // and the filename doesn't contain a dot --> probably a misspelled rule
1975 attributeError(attribute.getName(),
1976 "rule '" + prerequisiteLabel + "' does not exist");
1977 } else {
1978 attributeError(attribute.getName(),
1979 "target '" + prerequisiteLabel + "' does not exist");
1980 }
1981 } else {
1982 // The file exists but has a bad extension
lberkiee2dcae2018-03-28 05:49:04 -07001983 reportBadPrerequisite(attribute, prerequisite,
Ulf Adams07dba942015-03-05 14:47:37 +00001984 "expected " + attribute.getAllowedFileTypesPredicate(), false);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001985 }
1986 }
1987 }
1988 }
1989 }
1990
Michael Staib2707a882016-09-16 21:06:40 +00001991 /** Returns whether the context being constructed is for the evaluation of an aspect. */
1992 public boolean forAspect() {
dslomov44d15712017-12-20 05:42:28 -08001993 return !aspects.isEmpty();
Michael Staib2707a882016-09-16 21:06:40 +00001994 }
1995
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001996 public Rule getRule() {
lpino5fe7ed02018-07-18 05:55:23 -07001997 return target.getAssociatedRule();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001998 }
1999
Michael Staib8824d5e2016-01-20 21:37:05 +00002000 /**
Klaus Aehlig38053002019-10-29 09:54:32 -07002001 * Expose the Starlark semantics that governs the building of this rule (and the rest of the
2002 * build)
2003 */
2004 public StarlarkSemantics getStarlarkSemantics() throws InterruptedException {
2005 return env.getSkylarkSemantics();
2006 }
2007
2008 /**
Michael Staib8824d5e2016-01-20 21:37:05 +00002009 * Returns a rule class name suitable for log messages, including an aspect name if applicable.
2010 */
2011 public String getRuleClassNameForLogging() {
dslomov44d15712017-12-20 05:42:28 -08002012 if (aspects.isEmpty()) {
lpino5fe7ed02018-07-18 05:55:23 -07002013 return target.getAssociatedRule().getRuleClass();
Dmitry Lomov15756522016-12-16 16:52:37 +00002014 }
2015
dslomov44d15712017-12-20 05:42:28 -08002016 return Joiner.on(",")
2017 .join(aspects.stream().map(a -> a.getDescriptor()).collect(Collectors.toList()))
2018 + " aspect on "
lpino5fe7ed02018-07-18 05:55:23 -07002019 + target.getAssociatedRule().getRuleClass();
Michael Staib8824d5e2016-01-20 21:37:05 +00002020 }
2021
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002022 public BuildConfiguration getConfiguration() {
2023 return configuration;
2024 }
2025
2026 /**
2027 * @return true if {@code rule} is visible from {@code prerequisite}.
jcater0de10972020-04-07 12:15:05 -07002028 * <p>This only computes the logic as implemented by the visibility system. The final
2029 * decision whether a dependency is allowed is made by {@link PrerequisiteValidator}, who is
2030 * supposed to call this method to determine whether a dependency is allowed as per
2031 * visibility rules.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002032 */
2033 public boolean isVisible(TransitiveInfoCollection prerequisite) {
lpino5fe7ed02018-07-18 05:55:23 -07002034 return RuleContext.isVisible(target.getAssociatedRule(), prerequisite);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002035 }
2036
janakrf3e6f252018-01-18 07:45:12 -08002037 private void validateDirectPrerequisiteFileTypes(
janakr9c101402018-03-10 06:48:59 -08002038 ConfiguredTargetAndData prerequisite, Attribute attribute) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002039 if (attribute.isSkipAnalysisTimeFileTypeCheck()) {
2040 return;
2041 }
2042 FileTypeSet allowedFileTypes = attribute.getAllowedFileTypesPredicate();
Ulf Adams788fd1a2015-03-12 13:54:09 +00002043 if (allowedFileTypes == null) {
2044 // It's not a label or label_list attribute.
2045 return;
2046 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002047 if (allowedFileTypes == FileTypeSet.ANY_FILE && !attribute.isNonEmpty()
2048 && !attribute.isSingleArtifact()) {
2049 return;
2050 }
2051
2052 // If we allow any file we still need to check if there are actually files generated
2053 // Note that this check only runs for ANY_FILE predicates if the attribute is NON_EMPTY
2054 // or SINGLE_ARTIFACT
2055 // If we performed this check when allowedFileTypes == NO_FILE this would
2056 // always throw an error in those cases
2057 if (allowedFileTypes != FileTypeSet.NO_FILE) {
Ulf Adamscd31d3b2019-12-16 00:50:03 -08002058 NestedSet<Artifact> artifacts =
janakrf3e6f252018-01-18 07:45:12 -08002059 prerequisite.getConfiguredTarget().getProvider(FileProvider.class).getFilesToBuild();
Ulf Adamscd31d3b2019-12-16 00:50:03 -08002060 if (attribute.isSingleArtifact() && !artifacts.isSingleton()) {
janakrf3e6f252018-01-18 07:45:12 -08002061 attributeError(
2062 attribute.getName(),
2063 "'" + prerequisite.getTarget().getLabel() + "' must produce a single file");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002064 return;
2065 }
Ulf Adamscd31d3b2019-12-16 00:50:03 -08002066 for (Artifact sourceArtifact : artifacts.toList()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002067 if (allowedFileTypes.apply(sourceArtifact.getFilename())) {
2068 return;
2069 }
Googler2d90b6a2018-07-26 12:37:34 -07002070 if (sourceArtifact.isTreeArtifact()) {
2071 return;
2072 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002073 }
janakrf3e6f252018-01-18 07:45:12 -08002074 attributeError(
2075 attribute.getName(),
2076 "'"
2077 + prerequisite.getTarget().getLabel()
2078 + "' does not produce any "
2079 + getRuleClassNameForLogging()
2080 + " "
2081 + attribute.getName()
2082 + " files (expected "
2083 + allowedFileTypes
2084 + ")");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002085 }
2086 }
2087
dslomov7df85152017-08-01 20:47:59 +02002088 /**
dslomovc13bb392017-08-02 23:29:54 +02002089 * Because some rules still have to use allowedRuleClasses to do rule dependency validation. A
2090 * dependency is valid if it is from a rule in allowedRuledClasses, OR if all of the providers
2091 * in requiredProviders are provided by the target.
dslomov7df85152017-08-01 20:47:59 +02002092 */
janakr9c101402018-03-10 06:48:59 -08002093 private void validateRuleDependency(ConfiguredTargetAndData prerequisite, Attribute attribute) {
dslomov7df85152017-08-01 20:47:59 +02002094
dslomovc13bb392017-08-02 23:29:54 +02002095 Set<String> unfulfilledRequirements = new LinkedHashSet<>();
2096 if (checkRuleDependencyClass(prerequisite, attribute, unfulfilledRequirements)) {
2097 return;
2098 }
2099
2100 if (checkRuleDependencyClassWarnings(prerequisite, attribute)) {
2101 return;
2102 }
2103
2104 if (checkRuleDependencyMandatoryProviders(prerequisite, attribute, unfulfilledRequirements)) {
2105 return;
2106 }
2107
2108 // not allowed rule class and some mandatory providers missing => reject.
2109 if (!unfulfilledRequirements.isEmpty()) {
2110 attributeError(
2111 attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
2112 }
2113 }
2114
2115 /** Check if prerequisite should be allowed based on its rule class. */
2116 private boolean checkRuleDependencyClass(
janakr9c101402018-03-10 06:48:59 -08002117 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08002118 Attribute attribute,
2119 Set<String> unfulfilledRequirements) {
dslomovc32e1b12017-07-31 19:23:52 +02002120 if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
dslomovc13bb392017-08-02 23:29:54 +02002121 if (attribute
2122 .getAllowedRuleClassesPredicate()
2123 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002124 // prerequisite has an allowed rule class => accept.
dslomovc13bb392017-08-02 23:29:54 +02002125 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002126 }
2127 // remember that the rule class that was not allowed;
2128 // but maybe prerequisite provides required providers? do not reject yet.
dslomovc13bb392017-08-02 23:29:54 +02002129 unfulfilledRequirements.add(
dslomovc32e1b12017-07-31 19:23:52 +02002130 badPrerequisiteMessage(
dslomovc32e1b12017-07-31 19:23:52 +02002131 prerequisite,
2132 "expected " + attribute.getAllowedRuleClassesPredicate(),
dslomovc13bb392017-08-02 23:29:54 +02002133 false));
dslomovc32e1b12017-07-31 19:23:52 +02002134 }
dslomovc13bb392017-08-02 23:29:54 +02002135 return false;
2136 }
dslomovc32e1b12017-07-31 19:23:52 +02002137
dslomovc13bb392017-08-02 23:29:54 +02002138 /**
2139 * Check if prerequisite should be allowed with warning based on its rule class.
2140 *
2141 * <p>If yes, also issues said warning.
2142 */
2143 private boolean checkRuleDependencyClassWarnings(
janakr9c101402018-03-10 06:48:59 -08002144 ConfiguredTargetAndData prerequisite, Attribute attribute) {
dslomovc13bb392017-08-02 23:29:54 +02002145 if (attribute
2146 .getAllowedRuleClassesWarningPredicate()
2147 .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
dslomovc32e1b12017-07-31 19:23:52 +02002148 Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate();
dslomovc13bb392017-08-02 23:29:54 +02002149 reportBadPrerequisite(
2150 attribute,
dslomovc13bb392017-08-02 23:29:54 +02002151 prerequisite,
dslomovc32e1b12017-07-31 19:23:52 +02002152 allowedRuleClasses == Predicates.<RuleClass>alwaysTrue()
dslomovde965ac2017-07-31 21:07:51 +02002153 ? null
2154 : "expected " + allowedRuleClasses,
dslomovc32e1b12017-07-31 19:23:52 +02002155 true);
2156 // prerequisite has a rule class allowed with a warning => accept, emitting a warning.
dslomovc13bb392017-08-02 23:29:54 +02002157 return true;
2158 }
2159 return false;
2160 }
2161
2162 /** Check if prerequisite should be allowed based on required providers on the attribute. */
2163 private boolean checkRuleDependencyMandatoryProviders(
janakr9c101402018-03-10 06:48:59 -08002164 ConfiguredTargetAndData prerequisite,
janakrf3e6f252018-01-18 07:45:12 -08002165 Attribute attribute,
2166 Set<String> unfulfilledRequirements) {
dslomovc13bb392017-08-02 23:29:54 +02002167 RequiredProviders requiredProviders = attribute.getRequiredProviders();
2168
2169 if (requiredProviders.acceptsAny()) {
2170 // If no required providers specified, we do not know if we should accept.
2171 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002172 }
2173
janakrf3e6f252018-01-18 07:45:12 -08002174 if (prerequisite.getConfiguredTarget().satisfies(requiredProviders)) {
dslomovc13bb392017-08-02 23:29:54 +02002175 return true;
dslomovc32e1b12017-07-31 19:23:52 +02002176 }
2177
dslomovc13bb392017-08-02 23:29:54 +02002178 unfulfilledRequirements.add(
2179 String.format(
2180 "'%s' does not have mandatory providers: %s",
janakrf3e6f252018-01-18 07:45:12 -08002181 prerequisite.getTarget().getLabel(),
2182 prerequisite
2183 .getConfiguredTarget()
2184 .missingProviders(requiredProviders)
2185 .getDescription()));
dslomovc32e1b12017-07-31 19:23:52 +02002186
dslomovc13bb392017-08-02 23:29:54 +02002187 return false;
dslomovc32e1b12017-07-31 19:23:52 +02002188 }
2189
janakrf3e6f252018-01-18 07:45:12 -08002190 private void validateDirectPrerequisite(
janakr9c101402018-03-10 06:48:59 -08002191 Attribute attribute, ConfiguredTargetAndData prerequisite) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002192 validateDirectPrerequisiteType(prerequisite, attribute);
2193 validateDirectPrerequisiteFileTypes(prerequisite, attribute);
Greg Estren875c7a72015-09-24 19:57:54 +00002194 if (attribute.performPrereqValidatorCheck()) {
Ulf Adams0b638972015-09-08 13:25:35 +00002195 prerequisiteValidator.validate(this, prerequisite, attribute);
2196 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002197 }
2198 }
2199
ruperts8986b6e2017-10-17 00:26:29 +02002200 /** Helper class for reporting errors and warnings. */
cparsons963881a2018-10-03 14:23:55 -07002201 private static final class ErrorReporter extends EventHandlingErrorReporter
ruperts8986b6e2017-10-17 00:26:29 +02002202 implements RuleErrorConsumer {
Florian Weikertb8a6a942015-09-25 12:36:08 +00002203 private final Rule rule;
ulfjack07917642019-09-12 02:09:36 -07002204 private final BuildConfiguration configuration;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002205
ulfjack07917642019-09-12 02:09:36 -07002206 ErrorReporter(
2207 AnalysisEnvironment env,
2208 Rule rule,
2209 BuildConfiguration configuration,
2210 String ruleClassNameForLogging) {
asteinbb82db782018-05-18 08:21:39 -07002211 super(ruleClassNameForLogging, env);
Florian Weikertb8a6a942015-09-25 12:36:08 +00002212 this.rule = rule;
ulfjack07917642019-09-12 02:09:36 -07002213 this.configuration = configuration;
Florian Weikertb8a6a942015-09-25 12:36:08 +00002214 }
2215
2216 @Override
Googler706d75b2019-09-18 10:09:07 -07002217 protected String getMacroMessageAppendix(String unusedAttrName) {
2218 // TODO(b/141234726): Historically this reported the location
2219 // of the rule attribute in the macro call (assuming no **kwargs),
2220 // but we no longer locations for individual attributes.
2221 // We should record the instantiation call stack in each rule
2222 // and report the position of its topmost frame here.
asteinbb82db782018-05-18 08:21:39 -07002223 return rule.wasCreatedByMacro()
2224 ? String.format(
2225 ". Since this rule was created by the macro '%s', the error might have been "
Googler706d75b2019-09-18 10:09:07 -07002226 + "caused by the macro implementation",
2227 getGeneratorFunction())
asteinbb82db782018-05-18 08:21:39 -07002228 : "";
Florian Weikertb8a6a942015-09-25 12:36:08 +00002229 }
2230
Florian Weikertb8a6a942015-09-25 12:36:08 +00002231 private String getGeneratorFunction() {
2232 return (String) rule.getAttributeContainer().getAttr("generator_function");
2233 }
asteinbb82db782018-05-18 08:21:39 -07002234
2235 @Override
2236 protected Label getLabel() {
2237 return rule.getLabel();
2238 }
2239
2240 @Override
ulfjack07917642019-09-12 02:09:36 -07002241 protected BuildConfiguration getConfiguration() {
2242 return configuration;
2243 }
2244
2245 @Override
asteinbb82db782018-05-18 08:21:39 -07002246 protected Location getRuleLocation() {
2247 return rule.getLocation();
2248 }
cparsonse8d450c2018-10-04 16:01:53 -07002249 }
asteinbb82db782018-05-18 08:21:39 -07002250
cparsonse8d450c2018-10-04 16:01:53 -07002251 /**
2252 * Implementation of an error consumer which does not post any events, saves rule and attribute
2253 * errors for future consumption, and drops warnings.
2254 */
2255 public static final class SuppressingErrorReporter implements RuleErrorConsumer {
2256 private final List<String> errorMessages = Lists.newArrayList();
2257
2258 @Override
2259 public void ruleWarning(String message) {}
2260
2261 @Override
2262 public void ruleError(String message) {
2263 errorMessages.add(message);
2264 }
2265
2266 @Override
2267 public void attributeWarning(String attrName, String message) {}
2268
2269 @Override
2270 public void attributeError(String attrName, String message) {
2271 errorMessages.add(message);
2272 }
2273
2274 @Override
2275 public boolean hasErrors() {
2276 return !errorMessages.isEmpty();
2277 }
2278
2279 /**
2280 * Returns the error message strings reported to this error consumer.
2281 */
2282 public List<String> getErrorMessages() {
2283 return errorMessages;
2284 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002285 }
2286}