blob: 753b73ea6543c09aacadfa9e9b6f663e0bedec54 [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.packages;
16
Florian Weikertea6c82d2016-09-05 12:15:31 +000017import static com.google.devtools.build.lib.packages.Attribute.attr;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000018import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
19import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020
21import com.google.common.annotations.VisibleForTesting;
Lukacs Berki0e1a9942015-06-18 08:53:18 +000022import com.google.common.base.Function;
23import com.google.common.base.Functions;
tomlua155b532017-11-08 20:12:47 +010024import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010025import com.google.common.base.Predicate;
26import com.google.common.base.Predicates;
27import com.google.common.collect.ImmutableList;
Lukacs Berki0e1a9942015-06-18 08:53:18 +000028import com.google.common.collect.ImmutableMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.common.collect.ImmutableSet;
John Cater9a8d16e2017-07-05 16:12:07 -040030import com.google.common.collect.Iterables;
cpeyserd852e482017-09-07 22:16:06 +020031import com.google.common.collect.Lists;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032import com.google.common.collect.Ordering;
gregcebe55e112018-01-30 11:04:53 -080033import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
mstaib860975a2018-04-26 15:00:52 -070034import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
gregce74a895d2018-05-29 11:26:03 -070035import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000036import com.google.devtools.build.lib.cmdline.Label;
Lukacs Berkia6434362015-09-15 13:56:14 +000037import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
Brian Silvermand7d6d622016-03-17 09:53:39 +000038import com.google.devtools.build.lib.cmdline.PackageIdentifier;
dannarkf24479d2018-06-21 11:55:44 -070039import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010040import com.google.devtools.build.lib.events.EventHandler;
41import com.google.devtools.build.lib.events.Location;
Michajlo Matijkiw581f2c22016-07-25 20:12:16 +000042import com.google.devtools.build.lib.events.NullEventHandler;
Florian Weikertea6c82d2016-09-05 12:15:31 +000043import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate;
44import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate.CannotPrecomputeDefaultsException;
dannarkf24479d2018-06-21 11:55:44 -070045import com.google.devtools.build.lib.packages.BuildType.LabelConversionContext;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000046import com.google.devtools.build.lib.packages.BuildType.SelectorList;
Michael Staibb51251e2015-09-29 23:31:51 +000047import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy.MissingFragmentPolicy;
janakr6ff110e2018-03-21 21:44:27 -070048import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
nharmata65a173a2017-08-07 16:11:04 +020049import com.google.devtools.build.lib.packages.RuleFactory.AttributeValues;
mjhalupka49581922018-02-28 11:04:31 -080050import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
51import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010052import com.google.devtools.build.lib.syntax.Argument;
Francois-Rene Rideau95b0d0c2015-04-22 16:52:13 +000053import com.google.devtools.build.lib.syntax.BaseFunction;
Yue Gan36a26572016-05-25 11:48:10 +000054import com.google.devtools.build.lib.syntax.EvalException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010055import com.google.devtools.build.lib.syntax.FuncallExpression;
Francois-Rene Rideau0f7ba342015-08-31 16:16:21 +000056import com.google.devtools.build.lib.syntax.Runtime;
Francois-Rene Rideau93ed7f12015-10-20 15:39:33 +000057import com.google.devtools.build.lib.syntax.SkylarkList;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000058import com.google.devtools.build.lib.syntax.Type;
Mark Schalleree624452016-01-13 18:41:24 +000059import com.google.devtools.build.lib.syntax.Type.ConversionException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010060import com.google.devtools.build.lib.util.StringUtil;
61import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010062import java.util.ArrayList;
Googler72f3a102017-12-01 16:28:28 -080063import java.util.Arrays;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010064import java.util.BitSet;
65import java.util.Collection;
gregceda4c9592017-07-27 22:09:34 +020066import java.util.Collections;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010067import java.util.HashMap;
cpeyserfb829992017-09-07 17:17:03 +020068import java.util.HashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010069import java.util.LinkedHashMap;
70import java.util.LinkedHashSet;
71import java.util.List;
72import java.util.Map;
mjhalupka49581922018-02-28 11:04:31 -080073import java.util.Objects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074import java.util.Set;
75import java.util.regex.Pattern;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076import javax.annotation.Nullable;
77import javax.annotation.concurrent.Immutable;
78
79/**
80 * Instances of RuleClass encapsulate the set of attributes of a given "class" of rule, such as
81 * <code>cc_binary</code>.
82 *
janakrd3fe5e72018-03-30 12:49:12 -070083 * <p>This is an instance of the "meta-class" pattern for Rules: we achieve using <i>values</i> what
84 * subclasses achieve using <i>types</i>. (The "Design Patterns" book doesn't include this pattern,
85 * so think of it as something like a cross between a Flyweight and a State pattern. Like Flyweight,
86 * we avoid repeatedly storing data that belongs to many instances. Like State, we delegate from
87 * Rule to RuleClass for the specific behavior of that rule (though unlike state, a Rule object
88 * never changes its RuleClass). This avoids the need to declare one Java class per class of Rule,
89 * yet achieves the same behavior.)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090 *
91 * <p>The use of a metaclass also allows us to compute a mapping from Attributes to small integers
janakrd3fe5e72018-03-30 12:49:12 -070092 * and share this between all rules of the same metaclass. This means we can save the attribute
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010093 * dictionary for each rule instance using an array, which is much more compact than a hashtable.
94 *
95 * <p>Rule classes whose names start with "$" are considered "abstract"; since they are not valid
96 * identifiers, they cannot be named in the build language. However, they are useful for grouping
97 * related attributes which are inherited.
98 *
janakrd3fe5e72018-03-30 12:49:12 -070099 * <p>The exact values in this class are important. In particular:
100 *
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100101 * <ul>
janakrd3fe5e72018-03-30 12:49:12 -0700102 * <li>Changing an attribute from MANDATORY to OPTIONAL creates the potential for null-pointer
103 * exceptions in code that expects a value.
104 * <li>Attributes whose names are preceded by a "$" or a ":" are "hidden", and cannot be redefined
105 * in a BUILD file. They are a useful way of adding a special dependency. By convention,
106 * attributes starting with "$" are implicit dependencies, and those starting with a ":" are
107 * late-bound implicit dependencies, i.e. dependencies that can only be resolved when the
108 * configuration is known.
109 * <li>Attributes should not be introduced into the hierarchy higher then necessary.
110 * <li>The 'deps' and 'data' attributes are treated specially by the code that builds the runfiles
111 * tree. All targets appearing in these attributes appears beneath the ".runfiles" tree; in
112 * addition, "deps" may have rule-specific semantics.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100113 * </ul>
114 */
Janak Ramakrishnanc97ec7b2017-02-15 23:58:24 +0000115// Non-final only for mocking in tests. Do not subclass!
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100116@Immutable
janakrd3fe5e72018-03-30 12:49:12 -0700117@AutoCodec
Janak Ramakrishnanc97ec7b2017-02-15 23:58:24 +0000118public class RuleClass {
janakrd3fe5e72018-03-30 12:49:12 -0700119 @AutoCodec
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000120 static final Function<? super Rule, Map<String, Label>> NO_EXTERNAL_BINDINGS =
121 Functions.<Map<String, Label>>constant(ImmutableMap.<String, Label>of());
janakrd3fe5e72018-03-30 12:49:12 -0700122
123 @AutoCodec
mstaibe5538ad2017-04-04 18:32:23 +0000124 static final Function<? super Rule, Set<String>> NO_OPTION_REFERENCE =
125 Functions.<Set<String>>constant(ImmutableSet.<String>of());
Brian Silvermand7d6d622016-03-17 09:53:39 +0000126
nharmatab4060b62017-04-04 17:11:39 +0000127 public static final PathFragment THIRD_PARTY_PREFIX = PathFragment.create("third_party");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000128
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100129 /**
130 * A constraint for the package name of the Rule instances.
131 */
132 public static class PackageNameConstraint implements PredicateWithMessage<Rule> {
133
134 public static final int ANY_SEGMENT = 0;
135
136 private final int pathSegment;
137
138 private final Set<String> values;
139
140 /**
141 * The pathSegment-th segment of the package must be one of the specified values.
142 * The path segment indexing starts from 1.
143 */
144 public PackageNameConstraint(int pathSegment, String... values) {
145 this.values = ImmutableSet.copyOf(values);
146 this.pathSegment = pathSegment;
147 }
148
149 @Override
150 public boolean apply(Rule input) {
151 PathFragment path = input.getLabel().getPackageFragment();
152 if (pathSegment == ANY_SEGMENT) {
153 return path.getFirstSegment(values) != PathFragment.INVALID_SEGMENT;
154 } else {
155 return path.segmentCount() >= pathSegment
156 && values.contains(path.getSegment(pathSegment - 1));
157 }
158 }
159
160 @Override
161 public String getErrorReason(Rule param) {
162 if (pathSegment == ANY_SEGMENT) {
Francois-Rene Rideaucbebd632015-02-11 16:56:37 +0000163 return param.getRuleClass() + " rules have to be under a "
164 + StringUtil.joinEnglishList(values, "or", "'") + " directory";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100165 } else if (pathSegment == 1) {
166 return param.getRuleClass() + " rules are only allowed in "
167 + StringUtil.joinEnglishList(StringUtil.append(values, "//", ""), "or");
168 } else {
Francois-Rene Rideaucbebd632015-02-11 16:56:37 +0000169 return param.getRuleClass() + " rules are only allowed in packages which "
170 + StringUtil.ordinal(pathSegment) + " is " + StringUtil.joinEnglishList(values, "or");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100171 }
172 }
173
174 @VisibleForTesting
175 public int getPathSegment() {
176 return pathSegment;
177 }
178
179 @VisibleForTesting
180 public Collection<String> getValues() {
181 return values;
182 }
183 }
184
cparsonse2d200f2018-03-06 16:15:11 -0800185 /** A factory or builder class for rule implementations. */
186 public interface ConfiguredTargetFactory<
187 TConfiguredTarget, TContext, TActionConflictException extends Throwable> {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100188 /**
189 * Returns a fully initialized configured target instance using the given context.
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000190 *
191 * @throws RuleErrorException if configured target creation could not be completed due to rule
cparsonse2d200f2018-03-06 16:15:11 -0800192 * errors
193 * @throws TActionConflictException if there were conflicts during action registration
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100194 */
cparsonse2d200f2018-03-06 16:15:11 -0800195 TConfiguredTarget create(TContext ruleContext)
196 throws InterruptedException, RuleErrorException, TActionConflictException;
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000197
198 /**
cparsonse2d200f2018-03-06 16:15:11 -0800199 * Exception indicating that configured target creation could not be completed. General error
200 * messaging should be done via {@link RuleErrorConsumer}; this exception only interrupts
201 * configured target creation in cases where it can no longer continue.
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000202 */
203 public static final class RuleErrorException extends Exception {}
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100204 }
205
206 /**
John Cateree45c662018-06-05 11:09:01 -0700207 * Describes in which way a rule implementation allows additional execution platform constraints.
208 */
209 public enum ExecutionPlatformConstraintsAllowed {
210 /**
211 * Allows additional execution platform constraints to be added in the rule definition, which
212 * apply to all targets of that rule.
213 */
jcater01cc4792018-06-12 11:19:00 -0700214 PER_RULE(1),
John Cateree45c662018-06-05 11:09:01 -0700215 /**
216 * Users are allowed to specify additional execution platform constraints for each target, using
217 * the 'exec_compatible_with' attribute. This also allows setting constraints in the rule
218 * definition, like PER_RULE.
219 */
jcater01cc4792018-06-12 11:19:00 -0700220 PER_TARGET(2);
221
222 private final int priority;
223
224 ExecutionPlatformConstraintsAllowed(int priority) {
225 this.priority = priority;
226 }
227
228 public int priority() {
229 return priority;
230 }
231
232 public static ExecutionPlatformConstraintsAllowed highestPriority(
233 ExecutionPlatformConstraintsAllowed first, ExecutionPlatformConstraintsAllowed... rest) {
234 ExecutionPlatformConstraintsAllowed result = first;
235 for (ExecutionPlatformConstraintsAllowed value : rest) {
236 if (result == null || result.priority() < value.priority()) {
237 result = value;
238 }
239 }
240 return result;
241 }
John Cateree45c662018-06-05 11:09:01 -0700242 }
243
244 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100245 * For Bazel's constraint system: the attribute that declares the set of environments a rule
246 * supports, overriding the defaults for their respective groups.
247 */
248 public static final String RESTRICTED_ENVIRONMENT_ATTR = "restricted_to";
249
250 /**
251 * For Bazel's constraint system: the attribute that declares the set of environments a rule
252 * supports, appending them to the defaults for their respective groups.
253 */
254 public static final String COMPATIBLE_ENVIRONMENT_ATTR = "compatible_with";
255
256 /**
257 * For Bazel's constraint system: the implicit attribute used to store rule class restriction
258 * defaults as specified by {@link Builder#restrictedTo}.
259 */
260 public static final String DEFAULT_RESTRICTED_ENVIRONMENT_ATTR =
261 "$" + RESTRICTED_ENVIRONMENT_ATTR;
262
263 /**
264 * For Bazel's constraint system: the implicit attribute used to store rule class compatibility
265 * defaults as specified by {@link Builder#compatibleWith}.
266 */
267 public static final String DEFAULT_COMPATIBLE_ENVIRONMENT_ATTR =
268 "$" + COMPATIBLE_ENVIRONMENT_ATTR;
269
270 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100271 * A support class to make it easier to create {@code RuleClass} instances.
272 * This class follows the 'fluent builder' pattern.
273 *
274 * <p>The {@link #addAttribute} method will throw an exception if an attribute
275 * of that name already exists. Use {@link #overrideAttribute} in that case.
276 */
277 public static final class Builder {
Laurent Le Brun6ce51e12015-07-07 11:54:41 +0000278 private static final Pattern RULE_NAME_PATTERN = Pattern.compile("[A-Za-z_][A-Za-z0-9_]*");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100279
280 /**
281 * The type of the rule class, which determines valid names and required
282 * attributes.
283 */
284 public enum RuleClassType {
285 /**
286 * Abstract rules are intended for rule classes that are just used to
287 * factor out common attributes, and for rule classes that are used only
288 * internally. These rules cannot be instantiated by a BUILD file.
289 *
290 * <p>The rule name must contain a '$' and {@link
291 * TargetUtils#isTestRuleName} must return false for the name.
292 */
293 ABSTRACT {
294 @Override
295 public void checkName(String name) {
296 Preconditions.checkArgument(
Ulf Adams07dba942015-03-05 14:47:37 +0000297 (name.contains("$") && !TargetUtils.isTestRuleName(name)) || name.isEmpty());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100298 }
299
300 @Override
301 public void checkAttributes(Map<String, Attribute> attributes) {
302 // No required attributes.
303 }
304 },
305
306 /**
307 * Invisible rule classes should contain a dollar sign so that they cannot be instantiated
308 * by the user. They are different from abstract rules in that they can be instantiated
309 * at will.
310 */
311 INVISIBLE {
312 @Override
313 public void checkName(String name) {
314 Preconditions.checkArgument(name.contains("$"));
315 }
316
317 @Override
318 public void checkAttributes(Map<String, Attribute> attributes) {
319 // No required attributes.
320 }
321 },
322
323 /**
324 * Normal rules are instantiable by BUILD files. Their names must therefore
325 * obey the rules for identifiers in the BUILD language. In addition,
326 * {@link TargetUtils#isTestRuleName} must return false for the name.
327 */
328 NORMAL {
329 @Override
330 public void checkName(String name) {
Ulf Adams07dba942015-03-05 14:47:37 +0000331 Preconditions.checkArgument(
332 !TargetUtils.isTestRuleName(name) && RULE_NAME_PATTERN.matcher(name).matches(),
333 "Invalid rule name: %s", name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100334 }
335
336 @Override
337 public void checkAttributes(Map<String, Attribute> attributes) {
338 for (Attribute attribute : REQUIRED_ATTRIBUTES_FOR_NORMAL_RULES) {
339 Attribute presentAttribute = attributes.get(attribute.getName());
340 Preconditions.checkState(presentAttribute != null,
341 "Missing mandatory '%s' attribute in normal rule class.", attribute.getName());
342 Preconditions.checkState(presentAttribute.getType().equals(attribute.getType()),
Francois-Rene Rideaucbebd632015-02-11 16:56:37 +0000343 "Mandatory attribute '%s' in normal rule class has incorrect type (expected"
344 + " %s).", attribute.getName(), attribute.getType());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100345 }
346 }
347 },
348
349 /**
350 * Workspace rules can only be instantiated from a WORKSPACE file. Their names obey the
351 * rule for identifiers.
352 */
353 WORKSPACE {
354 @Override
355 public void checkName(String name) {
356 Preconditions.checkArgument(RULE_NAME_PATTERN.matcher(name).matches());
357 }
358
359 @Override
360 public void checkAttributes(Map<String, Attribute> attributes) {
361 // No required attributes.
362 }
363 },
364
365 /**
366 * Test rules are instantiable by BUILD files and are handled specially
367 * when run with the 'test' command. Their names must obey the rules
368 * for identifiers in the BUILD language and {@link
369 * TargetUtils#isTestRuleName} must return true for the name.
370 *
371 * <p>In addition, test rules must contain certain attributes. See {@link
372 * Builder#REQUIRED_ATTRIBUTES_FOR_TESTS}.
373 */
374 TEST {
375 @Override
376 public void checkName(String name) {
377 Preconditions.checkArgument(TargetUtils.isTestRuleName(name)
378 && RULE_NAME_PATTERN.matcher(name).matches());
379 }
380
381 @Override
382 public void checkAttributes(Map<String, Attribute> attributes) {
383 for (Attribute attribute : REQUIRED_ATTRIBUTES_FOR_TESTS) {
384 Attribute presentAttribute = attributes.get(attribute.getName());
385 Preconditions.checkState(presentAttribute != null,
386 "Missing mandatory '%s' attribute in test rule class.", attribute.getName());
387 Preconditions.checkState(presentAttribute.getType().equals(attribute.getType()),
Googleraa437e02017-09-14 09:52:47 +0200388 "Mandatory attribute '%s' in test rule class has incorrect type (expected %s).",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100389 attribute.getName(), attribute.getType());
390 }
391 }
Mark Schaller4fa83ac2015-07-10 16:59:37 +0000392 },
393
394 /**
395 * Placeholder rules are only instantiated when packages which refer to non-native rule
396 * classes are deserialized. At this time, non-native rule classes can't be serialized. To
397 * prevent crashes on deserialization, when a package containing a rule with a non-native rule
398 * class is deserialized, the rule is assigned a placeholder rule class. This is compatible
399 * with our limited set of package serialization use cases.
400 *
401 * Placeholder rule class names obey the rule for identifiers.
402 */
403 PLACEHOLDER {
404 @Override
405 public void checkName(String name) {
406 Preconditions.checkArgument(RULE_NAME_PATTERN.matcher(name).matches(), name);
407 }
408
409 @Override
410 public void checkAttributes(Map<String, Attribute> attributes) {
411 // No required attributes; this rule class cannot have the wrong set of attributes now
412 // because, if it did, the rule class would have failed to build before the package
413 // referring to it was serialized.
414 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100415 };
416
417 /**
418 * Checks whether the given name is valid for the current rule class type.
419 *
420 * @throws IllegalArgumentException if the name is not valid
421 */
422 public abstract void checkName(String name);
423
424 /**
425 * Checks whether the given set of attributes contains all the required
426 * attributes for the current rule class type.
427 *
428 * @throws IllegalArgumentException if a required attribute is missing
429 */
430 public abstract void checkAttributes(Map<String, Attribute> attributes);
431 }
432
Googler72f3a102017-12-01 16:28:28 -0800433 /** A predicate that filters rule classes based on their names. */
mjhalupka49581922018-02-28 11:04:31 -0800434 @AutoCodec
Googler72f3a102017-12-01 16:28:28 -0800435 public static class RuleClassNamePredicate {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100436
mjhalupka49581922018-02-28 11:04:31 -0800437 private static final RuleClassNamePredicate UNSPECIFIED_INSTANCE =
438 new RuleClassNamePredicate(ImmutableSet.of(), PredicateType.UNSPECIFIED, null);
439
440 private final ImmutableSet<String> ruleClassNames;
441
442 private final PredicateType predicateType;
443
Googler72f3a102017-12-01 16:28:28 -0800444 private final Predicate<String> ruleClassNamePredicate;
445 private final Predicate<RuleClass> ruleClassPredicate;
446 // if non-null, used ONLY for checking overlap
447 @Nullable private final Set<?> overlappable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100448
mjhalupka49581922018-02-28 11:04:31 -0800449 @VisibleForSerialization
450 enum PredicateType {
451 ONLY,
452 All_EXCEPT,
453 UNSPECIFIED
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100454 }
455
mjhalupka49581922018-02-28 11:04:31 -0800456 @VisibleForSerialization
457 RuleClassNamePredicate(
458 ImmutableSet<String> ruleClassNames, PredicateType predicateType, Set<?> overlappable) {
459 this.ruleClassNames = ruleClassNames;
460 this.predicateType = predicateType;
Googler72f3a102017-12-01 16:28:28 -0800461 this.overlappable = overlappable;
mjhalupka49581922018-02-28 11:04:31 -0800462
463 switch (predicateType) {
464 case All_EXCEPT:
465 Predicate<String> containing = only(ruleClassNames).asPredicateOfRuleClassName();
466 ruleClassNamePredicate =
467 new DescribedPredicate<>(
468 Predicates.not(containing), "all but " + containing.toString());
469 ruleClassPredicate =
470 new DescribedPredicate<>(
471 Predicates.compose(ruleClassNamePredicate, RuleClass::getName),
472 ruleClassNamePredicate.toString());
473 break;
474 case ONLY:
475 ruleClassNamePredicate =
476 new DescribedPredicate<>(
477 Predicates.in(ruleClassNames), StringUtil.joinEnglishList(ruleClassNames));
478 ruleClassPredicate =
479 new DescribedPredicate<>(
480 Predicates.compose(ruleClassNamePredicate, RuleClass::getName),
481 ruleClassNamePredicate.toString());
482 break;
483 case UNSPECIFIED:
484 ruleClassNamePredicate = Predicates.alwaysTrue();
485 ruleClassPredicate = Predicates.alwaysTrue();
486 break;
487 default:
488 // This shouldn't happen normally since the constructor is private and within this file.
489 throw new IllegalArgumentException(
490 "Predicate type was not specified when constructing a RuleClassNamePredicate.");
491 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100492 }
493
Googler72f3a102017-12-01 16:28:28 -0800494 public static RuleClassNamePredicate only(Iterable<String> ruleClassNamesAsIterable) {
495 ImmutableSet<String> ruleClassNames = ImmutableSet.copyOf(ruleClassNamesAsIterable);
mjhalupka49581922018-02-28 11:04:31 -0800496 return new RuleClassNamePredicate(ruleClassNames, PredicateType.ONLY, ruleClassNames);
Googler72f3a102017-12-01 16:28:28 -0800497 }
498
499 public static RuleClassNamePredicate only(String... ruleClasses) {
500 return only(Arrays.asList(ruleClasses));
501 }
502
503 public static RuleClassNamePredicate allExcept(String... ruleClasses) {
504 ImmutableSet<String> ruleClassNames = ImmutableSet.copyOf(ruleClasses);
505 Preconditions.checkState(!ruleClassNames.isEmpty(), "Use unspecified() instead");
mjhalupka49581922018-02-28 11:04:31 -0800506 return new RuleClassNamePredicate(ruleClassNames, PredicateType.All_EXCEPT, null);
Googler72f3a102017-12-01 16:28:28 -0800507 }
508
509 /**
510 * This is a special sentinel value which represents a "default" {@link
511 * RuleClassNamePredicate} which is unspecified. Note that a call to its {@link
512 * RuleClassNamePredicate#asPredicateOfRuleClass} produces {@code
513 * Predicates.<RuleClass>alwaysTrue()}, which is a sentinel value for other parts of bazel.
514 */
515 public static RuleClassNamePredicate unspecified() {
mjhalupka49581922018-02-28 11:04:31 -0800516 return UNSPECIFIED_INSTANCE;
Googler72f3a102017-12-01 16:28:28 -0800517 }
518
519 public final Predicate<String> asPredicateOfRuleClassName() {
520 return ruleClassNamePredicate;
521 }
522
523 public final Predicate<RuleClass> asPredicateOfRuleClass() {
524 return ruleClassPredicate;
525 }
526
527 /**
528 * Determines whether two {@code RuleClassNamePredicate}s should be considered incompatible as
529 * rule class predicate and rule class warning predicate.
530 *
531 * <p>Specifically, if both list sets of explicit rule class names to permit, those two sets
532 * must be disjoint, so the restriction only applies when both predicates have been created by
533 * {@link #only}.
534 */
535 boolean consideredOverlapping(RuleClassNamePredicate that) {
536 return this.overlappable != null
537 && that.overlappable != null
538 && !Collections.disjoint(this.overlappable, that.overlappable);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100539 }
540
541 @Override
542 public int hashCode() {
mjhalupka49581922018-02-28 11:04:31 -0800543 return Objects.hash(ruleClassNames, predicateType);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100544 }
545
546 @Override
Googler72f3a102017-12-01 16:28:28 -0800547 public boolean equals(Object obj) {
548 // NOTE: Specifically not checking equality of ruleClassPredicate.
549 // By construction, if the name predicates are equals, the rule class predicates are, too.
550 return obj instanceof RuleClassNamePredicate
mjhalupka49581922018-02-28 11:04:31 -0800551 && ruleClassNames.equals(((RuleClassNamePredicate) obj).ruleClassNames)
552 && predicateType.equals(((RuleClassNamePredicate) obj).predicateType);
gregceda4c9592017-07-27 22:09:34 +0200553 }
554
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100555 @Override
556 public String toString() {
Googler72f3a102017-12-01 16:28:28 -0800557 return ruleClassNamePredicate.toString();
558 }
559
560 /** A pass-through predicate, except that an explicit {@link #toString()} is provided. */
561 private static class DescribedPredicate<T> implements Predicate<T> {
562 private final Predicate<T> delegate; // the actual predicate
563 private final String description;
564
565 private DescribedPredicate(Predicate<T> delegate, String description) {
566 this.delegate = delegate;
567 this.description = description;
568 }
569
570 @Override
571 public boolean apply(T input) {
572 return delegate.apply(input);
573 }
574
575 @Override
576 public int hashCode() {
577 return delegate.hashCode();
578 }
579
580 @Override
581 public boolean equals(Object obj) {
582 return obj instanceof DescribedPredicate
583 && delegate.equals(((DescribedPredicate<?>) obj).delegate);
584 }
585
586 @Override
587 public String toString() {
588 return description;
589 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100590 }
591 }
592
janakrd3fe5e72018-03-30 12:49:12 -0700593 /** A RuleTransitionFactory which always returns the same transition. */
594 @AutoCodec.VisibleForSerialization
595 @AutoCodec
596 static final class FixedTransitionFactory implements RuleTransitionFactory {
mstaib860975a2018-04-26 15:00:52 -0700597 private final PatchTransition transition;
Michael Staib2a675202017-03-20 18:06:48 +0000598
janakrd3fe5e72018-03-30 12:49:12 -0700599 @AutoCodec.VisibleForSerialization
mstaib860975a2018-04-26 15:00:52 -0700600 FixedTransitionFactory(PatchTransition transition) {
Michael Staib2a675202017-03-20 18:06:48 +0000601 this.transition = transition;
602 }
603
604 @Override
mstaib860975a2018-04-26 15:00:52 -0700605 public PatchTransition buildTransitionFor(Rule rule) {
Michael Staib2a675202017-03-20 18:06:48 +0000606 return transition;
607 }
608 }
609
Googler7807b6c2017-03-14 10:57:43 +0000610 /** List of required attributes for normal rules, name and type. */
611 public static final ImmutableList<Attribute> REQUIRED_ATTRIBUTES_FOR_NORMAL_RULES =
612 ImmutableList.of(attr("tags", Type.STRING_LIST).build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100613
Googler7807b6c2017-03-14 10:57:43 +0000614 /** List of required attributes for test rules, name and type. */
615 public static final ImmutableList<Attribute> REQUIRED_ATTRIBUTES_FOR_TESTS =
616 ImmutableList.of(
617 attr("tags", Type.STRING_LIST).build(),
618 attr("size", Type.STRING).build(),
619 attr("timeout", Type.STRING).build(),
620 attr("flaky", Type.BOOLEAN).build(),
621 attr("shard_count", Type.INTEGER).build(),
622 attr("local", Type.BOOLEAN).build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100623
624 private String name;
625 private final RuleClassType type;
626 private final boolean skylark;
Jon Brandveinead58ae2016-09-29 18:41:10 +0000627 private boolean skylarkTestable = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100628 private boolean documented;
629 private boolean publicByDefault = false;
630 private boolean binaryOutput = true;
631 private boolean workspaceOnly = false;
dslomov2ce98442017-10-23 19:14:02 +0200632 private boolean isExecutableSkylark = false;
cparsons55781c92018-10-17 12:03:08 -0700633 private boolean isAnalysisTest = false;
mstaibdf229582017-03-31 21:50:46 +0000634 private boolean isConfigMatcher = false;
Googlerc2200fd2018-09-14 17:35:59 -0700635 private boolean hasFunctionTransitionWhitelist = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100636 private ImplicitOutputsFunction implicitOutputsFunction = ImplicitOutputsFunction.NONE;
Michael Staib2a675202017-03-20 18:06:48 +0000637 private RuleTransitionFactory transitionFactory;
cparsonse2d200f2018-03-06 16:15:11 -0800638 private ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory = null;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100639 private PredicateWithMessage<Rule> validityPredicate =
640 PredicatesWithMessage.<Rule>alwaysTrue();
641 private Predicate<String> preferredDependencyPredicate = Predicates.alwaysFalse();
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000642 private AdvertisedProviderSet.Builder advertisedProviders = AdvertisedProviderSet.builder();
Francois-Rene Rideau95b0d0c2015-04-22 16:52:13 +0000643 private BaseFunction configuredTargetFunction = null;
Lukacs Berki0e1a9942015-06-18 08:53:18 +0000644 private Function<? super Rule, Map<String, Label>> externalBindingsFunction =
645 NO_EXTERNAL_BINDINGS;
mstaibe5538ad2017-04-04 18:32:23 +0000646 private Function<? super Rule, ? extends Set<String>> optionReferenceFunction =
647 NO_OPTION_REFERENCE;
janakrd3fe5e72018-03-30 12:49:12 -0700648 /** This field and the next are null iff the rule is native. */
649 @Nullable private Label ruleDefinitionEnvironmentLabel;
650
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000651 @Nullable private String ruleDefinitionEnvironmentHashCode = null;
Michael Staibb51251e2015-09-29 23:31:51 +0000652 private ConfigurationFragmentPolicy.Builder configurationFragmentPolicy =
653 new ConfigurationFragmentPolicy.Builder();
Florian Weikert3f53fbb2015-08-07 22:25:50 +0000654
Greg Estrenc04c88f2015-03-06 19:45:50 +0000655 private boolean supportsConstraintChecking = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100656
657 private final Map<String, Attribute> attributes = new LinkedHashMap<>();
cpeyserfb829992017-09-07 17:17:03 +0200658 private final Set<Label> requiredToolchains = new HashSet<>();
John Cater856b4dd2017-11-21 08:06:16 -0800659 private boolean supportsPlatforms = true;
John Cateree45c662018-06-05 11:09:01 -0700660 private ExecutionPlatformConstraintsAllowed executionPlatformConstraintsAllowed =
661 ExecutionPlatformConstraintsAllowed.PER_RULE;
662 private Set<Label> executionPlatformConstraints = new HashSet<>();
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700663 private OutputFile.Kind outputFileKind = OutputFile.Kind.FILE;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100664
665 /**
666 * Constructs a new {@code RuleClassBuilder} using all attributes from all
667 * parent rule classes. An attribute cannot exist in more than one parent.
668 *
gregce64c36e12017-07-26 23:48:56 +0200669 * <p>The rule type affects the allowed names and the required
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100670 * attributes (see {@link RuleClassType}).
671 *
672 * @throws IllegalArgumentException if an attribute with the same name exists
673 * in more than one parent
674 */
675 public Builder(String name, RuleClassType type, boolean skylark, RuleClass... parents) {
676 this.name = name;
677 this.skylark = skylark;
678 this.type = type;
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000679 Preconditions.checkState(skylark || type != RuleClassType.PLACEHOLDER, name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100680 this.documented = type != RuleClassType.ABSTRACT;
681 for (RuleClass parent : parents) {
682 if (parent.getValidityPredicate() != PredicatesWithMessage.<Rule>alwaysTrue()) {
683 setValidityPredicate(parent.getValidityPredicate());
684 }
685 if (parent.preferredDependencyPredicate != Predicates.<String>alwaysFalse()) {
686 setPreferredDependencyPredicate(parent.preferredDependencyPredicate);
687 }
Michael Staibff66c192016-01-14 22:40:37 +0000688 configurationFragmentPolicy
689 .includeConfigurationFragmentsFrom(parent.getConfigurationFragmentPolicy());
Michael Staibb51251e2015-09-29 23:31:51 +0000690 configurationFragmentPolicy.setMissingFragmentPolicy(
691 parent.getConfigurationFragmentPolicy().getMissingFragmentPolicy());
Greg Estrenc04c88f2015-03-06 19:45:50 +0000692 supportsConstraintChecking = parent.supportsConstraintChecking;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100693
cpeyserd78b3742017-08-04 19:48:53 +0200694 addRequiredToolchains(parent.getRequiredToolchains());
John Cater856b4dd2017-11-21 08:06:16 -0800695 supportsPlatforms = parent.supportsPlatforms;
jcater01cc4792018-06-12 11:19:00 -0700696
697 // Make sure we use the highest priority value from all parents.
698 executionPlatformConstraintsAllowed(
699 ExecutionPlatformConstraintsAllowed.highestPriority(
700 executionPlatformConstraintsAllowed, parent.executionPlatformConstraintsAllowed()));
John Cateree45c662018-06-05 11:09:01 -0700701 addExecutionPlatformConstraints(parent.getExecutionPlatformConstraints());
cpeyserd78b3742017-08-04 19:48:53 +0200702
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100703 for (Attribute attribute : parent.getAttributes()) {
704 String attrName = attribute.getName();
705 Preconditions.checkArgument(
dannarke64a8162018-06-13 13:48:20 -0700706 !attributes.containsKey(attrName) || attributes.get(attrName).equals(attribute),
Googler2935d672015-03-12 01:25:11 +0000707 "Attribute %s is inherited multiple times in %s ruleclass",
708 attrName,
709 name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100710 attributes.put(attrName, attribute);
711 }
Lukacs Berkiac4f9422015-05-29 10:06:30 +0000712
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000713 advertisedProviders.addParent(parent.getAdvertisedProviders());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100714 }
715 // TODO(bazel-team): move this testonly attribute setting to somewhere else
716 // preferably to some base RuleClass implementation.
717 if (this.type.equals(RuleClassType.TEST)) {
718 Attribute.Builder<Boolean> testOnlyAttr = attr("testonly", BOOLEAN).value(true)
719 .nonconfigurable("policy decision: this shouldn't depend on the configuration");
720 if (attributes.containsKey("testonly")) {
721 override(testOnlyAttr);
722 } else {
723 add(testOnlyAttr);
724 }
725 }
726 }
727
728 /**
729 * Checks that required attributes for test rules are present, creates the
730 * {@link RuleClass} object and returns it.
731 *
732 * @throws IllegalStateException if any of the required attributes is missing
733 */
734 public RuleClass build() {
tomlu72642a22017-10-18 06:23:14 +0200735 // For built-ins, name == key
736 return build(name, name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100737 }
738
tomlu72642a22017-10-18 06:23:14 +0200739 /** Same as {@link #build} except with setting the name and key parameters. */
740 public RuleClass build(String name, String key) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100741 Preconditions.checkArgument(this.name.isEmpty() || this.name.equals(name));
742 type.checkName(name);
743 type.checkAttributes(attributes);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100744 Preconditions.checkState(
745 (type == RuleClassType.ABSTRACT)
janakr6ff110e2018-03-21 21:44:27 -0700746 == (configuredTargetFactory == null && configuredTargetFunction == null),
747 "Bad combo for %s: %s %s %s",
748 name,
749 type,
750 configuredTargetFactory,
751 configuredTargetFunction);
Damien Martin-Guillerez653df882016-02-17 21:46:22 +0000752 if (!workspaceOnly) {
janakrd3fe5e72018-03-30 12:49:12 -0700753 if (skylark) {
754 assertSkylarkRuleClassHasImplementationFunction();
755 assertSkylarkRuleClassHasEnvironmentLabel();
756 }
Damien Martin-Guillerez653df882016-02-17 21:46:22 +0000757 Preconditions.checkState(externalBindingsFunction == NO_EXTERNAL_BINDINGS);
758 }
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000759 if (type == RuleClassType.PLACEHOLDER) {
760 Preconditions.checkNotNull(ruleDefinitionEnvironmentHashCode, this.name);
761 }
jcater5f292bb2018-06-19 14:14:34 -0700762 if (executionPlatformConstraintsAllowed == ExecutionPlatformConstraintsAllowed.PER_TARGET
763 && !this.contains("exec_compatible_with")) {
John Cateree45c662018-06-05 11:09:01 -0700764 this.add(
765 attr("exec_compatible_with", BuildType.LABEL_LIST)
766 .allowedFileTypes()
767 .nonconfigurable("Used in toolchain resolution")
768 .value(ImmutableList.of()));
769 }
Googlerc2200fd2018-09-14 17:35:59 -0700770 if (skylark) {
771 assertSkylarkRuleClassProperFunctionTransitionUsage();
772 }
John Cateree45c662018-06-05 11:09:01 -0700773
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000774 return new RuleClass(
775 name,
tomlu72642a22017-10-18 06:23:14 +0200776 key,
janakr6ff110e2018-03-21 21:44:27 -0700777 type,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000778 skylark,
Jon Brandveinead58ae2016-09-29 18:41:10 +0000779 skylarkTestable,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000780 documented,
781 publicByDefault,
782 binaryOutput,
783 workspaceOnly,
dslomov2ce98442017-10-23 19:14:02 +0200784 isExecutableSkylark,
cparsons55781c92018-10-17 12:03:08 -0700785 isAnalysisTest,
Googlerc2200fd2018-09-14 17:35:59 -0700786 hasFunctionTransitionWhitelist,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000787 implicitOutputsFunction,
mstaibdf229582017-03-31 21:50:46 +0000788 isConfigMatcher,
Michael Staib2a675202017-03-20 18:06:48 +0000789 transitionFactory,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000790 configuredTargetFactory,
791 validityPredicate,
792 preferredDependencyPredicate,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000793 advertisedProviders.build(),
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000794 configuredTargetFunction,
795 externalBindingsFunction,
mstaibe5538ad2017-04-04 18:32:23 +0000796 optionReferenceFunction,
janakrd3fe5e72018-03-30 12:49:12 -0700797 ruleDefinitionEnvironmentLabel,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000798 ruleDefinitionEnvironmentHashCode,
799 configurationFragmentPolicy.build(),
800 supportsConstraintChecking,
John Catereca28402017-05-17 21:44:12 +0200801 requiredToolchains,
John Cater856b4dd2017-11-21 08:06:16 -0800802 supportsPlatforms,
John Cateree45c662018-06-05 11:09:01 -0700803 executionPlatformConstraintsAllowed,
804 executionPlatformConstraints,
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700805 outputFileKind,
janakrd3fe5e72018-03-30 12:49:12 -0700806 attributes.values());
807 }
808
809 private void assertSkylarkRuleClassHasImplementationFunction() {
810 Preconditions.checkState(
811 (type == RuleClassType.NORMAL || type == RuleClassType.TEST)
812 == (configuredTargetFunction != null),
813 "%s %s",
814 type,
815 configuredTargetFunction);
816 }
817
818 private void assertSkylarkRuleClassHasEnvironmentLabel() {
819 Preconditions.checkState(
820 (type == RuleClassType.NORMAL
821 || type == RuleClassType.TEST
822 || type == RuleClassType.PLACEHOLDER)
823 == (ruleDefinitionEnvironmentLabel != null),
824 "Concrete Skylark rule classes can't have null labels: %s %s",
825 ruleDefinitionEnvironmentLabel,
826 type);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100827 }
828
Googlerc2200fd2018-09-14 17:35:59 -0700829 private void assertSkylarkRuleClassProperFunctionTransitionUsage() {
830 boolean hasFunctionTransitionAttribute =
831 attributes.entrySet()
832 .stream()
833 .map(entry -> entry.getValue().hasFunctionTransition())
834 .reduce(false, (a, b) -> a || b);
835
836 if (hasFunctionTransitionAttribute) {
837 Preconditions.checkState(
838 hasFunctionTransitionWhitelist,
839 "Use of function based split transition without whitelist: %s %s",
840 ruleDefinitionEnvironmentLabel,
841 type);
842 } else {
843 Preconditions.checkState(
844 !hasFunctionTransitionWhitelist,
845 "Unused function based split transition whitelist: %s %s",
846 ruleDefinitionEnvironmentLabel,
847 type);
848 }
849 }
850
851 /**
Greg Estren693f17f2015-11-06 16:45:45 +0000852 * Declares that the implementation of the associated rule class requires the given
853 * fragments to be present in this rule's host and target configurations.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100854 *
Greg Estren693f17f2015-11-06 16:45:45 +0000855 * <p>The value is inherited by subclasses.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100856 */
Michael Staibb51251e2015-09-29 23:31:51 +0000857 public Builder requiresConfigurationFragments(Class<?>... configurationFragments) {
Michael Staibff66c192016-01-14 22:40:37 +0000858 configurationFragmentPolicy.requiresConfigurationFragments(
859 ImmutableSet.<Class<?>>copyOf(configurationFragments));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100860 return this;
861 }
862
Ulf Adams71423eb2015-08-06 11:51:17 +0000863 /**
Greg Estren693f17f2015-11-06 16:45:45 +0000864 * Declares that the implementation of the associated rule class requires the given
gregce614dc502017-12-20 17:24:46 -0800865 * fragments to be present in the given configuration that isn't the rule's configuration but
866 * is also readable by the rule.
867 *
868 * <p>You probably don't want to use this, because rules generally shouldn't read configurations
869 * other than their own. If you want to declare host config fragments, see
870 * {@link com.google.devtools.build.lib.analysis.config.ConfigAwareRuleClassBuilder}.
Greg Estren693f17f2015-11-06 16:45:45 +0000871 *
872 * <p>The value is inherited by subclasses.
873 */
gregcebe55e112018-01-30 11:04:53 -0800874 public Builder requiresConfigurationFragments(ConfigurationTransition transition,
gregce614dc502017-12-20 17:24:46 -0800875 Class<?>... configurationFragments) {
876 configurationFragmentPolicy.requiresConfigurationFragments(
877 transition,
Michael Staibff66c192016-01-14 22:40:37 +0000878 ImmutableSet.<Class<?>>copyOf(configurationFragments));
Greg Estren693f17f2015-11-06 16:45:45 +0000879 return this;
880 }
881
882 /**
Michael Staibff66c192016-01-14 22:40:37 +0000883 * Declares the configuration fragments that are required by this rule for the target
884 * configuration.
Greg Estren693f17f2015-11-06 16:45:45 +0000885 *
886 * <p>In contrast to {@link #requiresConfigurationFragments(Class...)}, this method takes the
Michael Staibff66c192016-01-14 22:40:37 +0000887 * Skylark module names of fragments instead of their classes.
Greg Estren693f17f2015-11-06 16:45:45 +0000888 */
Michael Staibff66c192016-01-14 22:40:37 +0000889 public Builder requiresConfigurationFragmentsBySkylarkModuleName(
890 Collection<String> configurationFragmentNames) {
891 configurationFragmentPolicy
892 .requiresConfigurationFragmentsBySkylarkModuleName(configurationFragmentNames);
893 return this;
894 }
895
896 /**
897 * Declares the configuration fragments that are required by this rule for the host
898 * configuration.
899 *
Michael Staibff66c192016-01-14 22:40:37 +0000900 */
gregce614dc502017-12-20 17:24:46 -0800901 /**
902 * Declares that the implementation of the associated rule class requires the given
903 * fragments to be present in the given configuration that isn't the rule's configuration but
904 * is also readable by the rule.
905 *
gregcebe55e112018-01-30 11:04:53 -0800906 * <p>In contrast to {@link #requiresConfigurationFragments(ConfigurationTransition, Class...)},
907 * this method takes Skylark module names of fragments instead of their classes.
gregce614dc502017-12-20 17:24:46 -0800908 * *
909 * <p>You probably don't want to use this, because rules generally shouldn't read configurations
910 * other than their own. If you want to declare host config fragments, see
911 * {@link com.google.devtools.build.lib.analysis.config.ConfigAwareRuleClassBuilder}.
912 *
913 * <p>The value is inherited by subclasses.
914 */
gregcebe55e112018-01-30 11:04:53 -0800915 public Builder requiresConfigurationFragmentsBySkylarkModuleName(
916 ConfigurationTransition transition, Collection<String> configurationFragmentNames) {
gregce614dc502017-12-20 17:24:46 -0800917 configurationFragmentPolicy.requiresConfigurationFragmentsBySkylarkModuleName(transition,
918 configurationFragmentNames);
Greg Estren693f17f2015-11-06 16:45:45 +0000919 return this;
920 }
921
Jon Brandveinead58ae2016-09-29 18:41:10 +0000922 public Builder setSkylarkTestable() {
923 Preconditions.checkState(skylark, "Cannot set skylarkTestable on a non-Skylark rule");
924 skylarkTestable = true;
925 return this;
926 }
927
Greg Estren693f17f2015-11-06 16:45:45 +0000928 /**
Ulf Adams71423eb2015-08-06 11:51:17 +0000929 * Sets the policy for the case where the configuration is missing required fragments (see
930 * {@link #requiresConfigurationFragments}).
931 */
932 public Builder setMissingFragmentPolicy(MissingFragmentPolicy missingFragmentPolicy) {
Michael Staibb51251e2015-09-29 23:31:51 +0000933 configurationFragmentPolicy.setMissingFragmentPolicy(missingFragmentPolicy);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100934 return this;
935 }
Florian Weikert3f8aac92015-09-07 12:06:02 +0000936
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100937 public Builder setUndocumented() {
938 documented = false;
939 return this;
940 }
941
942 public Builder publicByDefault() {
943 publicByDefault = true;
944 return this;
945 }
946
947 public Builder setWorkspaceOnly() {
948 workspaceOnly = true;
949 return this;
950 }
951
952 /**
953 * Determines the outputs of this rule to be created beneath the {@code
954 * genfiles} directory. By default, files are created beneath the {@code bin}
955 * directory.
956 *
957 * <p>This property is not inherited and this method should not be called by
958 * builder of {@link RuleClassType#ABSTRACT} rule class.
959 *
960 * @throws IllegalStateException if called for abstract rule class builder
961 */
962 public Builder setOutputToGenfiles() {
963 Preconditions.checkState(type != RuleClassType.ABSTRACT,
964 "Setting not inherited property (output to genrules) of abstract rule class '%s'", name);
965 this.binaryOutput = false;
966 return this;
967 }
968
969 /**
970 * Sets the implicit outputs function of the rule class. The default implicit
971 * outputs function is {@link ImplicitOutputsFunction#NONE}.
972 *
973 * <p>This property is not inherited and this method should not be called by
974 * builder of {@link RuleClassType#ABSTRACT} rule class.
975 *
976 * @throws IllegalStateException if called for abstract rule class builder
977 */
978 public Builder setImplicitOutputsFunction(
979 ImplicitOutputsFunction implicitOutputsFunction) {
980 Preconditions.checkState(type != RuleClassType.ABSTRACT,
981 "Setting not inherited property (implicit output function) of abstract rule class '%s'",
982 name);
983 this.implicitOutputsFunction = implicitOutputsFunction;
984 return this;
985 }
986
Cal Peyser19dda252017-01-11 23:37:05 +0000987 /**
gregce64c36e12017-07-26 23:48:56 +0200988 * Applies the given transition to all incoming edges for this rule class.
Cal Peyser19dda252017-01-11 23:37:05 +0000989 *
gregce74a895d2018-05-29 11:26:03 -0700990 * <p>This cannot be a {@link SplitTransition} because that requires coordination with the
991 * rule's parent: use {@link Attribute.Builder#cfg(ConfigurationTransition)} on the parent to
992 * declare splits.
993 *
gregce64c36e12017-07-26 23:48:56 +0200994 * <p>If you need the transition to depend on the rule it's being applied to, use
995 * {@link #cfg(RuleTransitionFactory)}.
Cal Peyser19dda252017-01-11 23:37:05 +0000996 */
mstaib860975a2018-04-26 15:00:52 -0700997 public Builder cfg(PatchTransition transition) {
gregce74a895d2018-05-29 11:26:03 -0700998 return cfg(new FixedTransitionFactory(transition));
Michael Staib2a675202017-03-20 18:06:48 +0000999 }
1000
gregce64c36e12017-07-26 23:48:56 +02001001 /**
1002 * Applies the given transition factory to all incoming edges for this rule class.
1003 *
John Cateree45c662018-06-05 11:09:01 -07001004 * <p>Unlike {@link #cfg(PatchTransition)}, the factory can examine the rule when deciding what
1005 * transition to use.
gregce64c36e12017-07-26 23:48:56 +02001006 */
Michael Staib2a675202017-03-20 18:06:48 +00001007 public Builder cfg(RuleTransitionFactory transitionFactory) {
1008 Preconditions.checkState(type != RuleClassType.ABSTRACT,
1009 "Setting not inherited property (cfg) of abstract rule class '%s'", name);
gregcef19fcfe2017-06-02 16:04:07 -04001010 Preconditions.checkState(this.transitionFactory == null,
Michael Staib2a675202017-03-20 18:06:48 +00001011 "Property cfg has already been set");
1012 Preconditions.checkNotNull(transitionFactory);
1013 this.transitionFactory = transitionFactory;
Cal Peyser19dda252017-01-11 23:37:05 +00001014 return this;
1015 }
1016
cparsonse2d200f2018-03-06 16:15:11 -08001017 public Builder factory(ConfiguredTargetFactory<?, ?, ?> factory) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001018 this.configuredTargetFactory = factory;
1019 return this;
1020 }
1021
1022 public Builder setValidityPredicate(PredicateWithMessage<Rule> predicate) {
1023 this.validityPredicate = predicate;
1024 return this;
1025 }
1026
1027 public Builder setPreferredDependencyPredicate(Predicate<String> predicate) {
1028 this.preferredDependencyPredicate = predicate;
1029 return this;
1030 }
1031
1032 /**
1033 * State that the rule class being built possibly supplies the specified provider to its direct
1034 * dependencies.
1035 *
1036 * <p>When computing the set of aspects required for a rule, only the providers listed here are
1037 * considered. The presence of a provider here does not mean that the rule <b>must</b> implement
1038 * said provider, merely that it <b>can</b>. After the configured target is constructed from
1039 * this rule, aspects will be filtered according to the set of actual providers.
1040 *
1041 * <p>This is here so that we can do the loading phase overestimation required for
1042 * "blaze query", which does not have the configured targets available.
1043 *
1044 * <p>It's okay for the rule class eventually not to supply it (possibly based on analysis phase
1045 * logic), but if a provider is not advertised but is supplied, aspects that require the it will
1046 * not be evaluated for the rule.
1047 */
1048 public Builder advertiseProvider(Class<?>... providers) {
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001049 for (Class<?> provider : providers) {
1050 advertisedProviders.addNative(provider);
1051 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001052 return this;
1053 }
1054
elenairinaaeb21bc2017-09-27 12:13:52 -04001055 public Builder advertiseSkylarkProvider(SkylarkProviderIdentifier... skylarkProviders) {
1056 for (SkylarkProviderIdentifier skylarkProviderIdentifier : skylarkProviders) {
1057 advertisedProviders.addSkylark(skylarkProviderIdentifier);
1058 }
1059 return this;
1060 }
1061
Lukacs Berki549bfce2016-04-22 15:29:12 +00001062 /**
1063 * Set if the rule can have any provider. This is true for "alias" rules like
1064 * <code>bind</code> .
1065 */
1066 public Builder canHaveAnyProvider() {
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001067 advertisedProviders.canHaveAnyProvider();
Lukacs Berki549bfce2016-04-22 15:29:12 +00001068 return this;
1069 }
1070
dbabkina2823422018-05-02 02:42:53 -07001071 public Builder addAttribute(Attribute attribute) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001072 Preconditions.checkState(!attributes.containsKey(attribute.getName()),
1073 "An attribute with the name '%s' already exists.", attribute.getName());
1074 attributes.put(attribute.getName(), attribute);
dbabkina2823422018-05-02 02:42:53 -07001075 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001076 }
1077
1078 private void overrideAttribute(Attribute attribute) {
1079 String attrName = attribute.getName();
1080 Preconditions.checkState(attributes.containsKey(attrName),
1081 "No such attribute '%s' to override in ruleclass '%s'.", attrName, name);
1082 Type<?> origType = attributes.get(attrName).getType();
1083 Type<?> newType = attribute.getType();
1084 Preconditions.checkState(origType.equals(newType),
1085 "The type of the new attribute '%s' is different from the original one '%s'.",
1086 newType, origType);
1087 attributes.put(attrName, attribute);
1088 }
1089
1090 /**
1091 * Builds attribute from the attribute builder and adds it to this rule
1092 * class.
1093 *
1094 * @param attr attribute builder
1095 */
1096 public <TYPE> Builder add(Attribute.Builder<TYPE> attr) {
1097 addAttribute(attr.build());
1098 return this;
1099 }
1100
1101 /**
1102 * Builds attribute from the attribute builder and overrides the attribute
1103 * with the same name.
1104 *
1105 * @throws IllegalArgumentException if the attribute does not override one of the same name
1106 */
1107 public <TYPE> Builder override(Attribute.Builder<TYPE> attr) {
1108 overrideAttribute(attr.build());
1109 return this;
1110 }
1111
1112 /**
1113 * Adds or overrides the attribute in the rule class. Meant for Skylark usage.
Florian Weikerte96b0b82015-09-25 11:35:11 +00001114 *
1115 * @throws IllegalArgumentException if the attribute overrides an existing attribute (will be
1116 * legal in the future).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001117 */
1118 public void addOrOverrideAttribute(Attribute attribute) {
Florian Weikerte96b0b82015-09-25 11:35:11 +00001119 String name = attribute.getName();
1120 // Attributes may be overridden in the future.
1121 Preconditions.checkArgument(!attributes.containsKey(name),
1122 "There is already a built-in attribute '%s' which cannot be overridden", name);
1123 addAttribute(attribute);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001124 }
1125
Mark Schaller4fa83ac2015-07-10 16:59:37 +00001126 /** True if the rule class contains an attribute named {@code name}. */
1127 public boolean contains(String name) {
1128 return attributes.containsKey(name);
1129 }
1130
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001131 /**
1132 * Sets the rule implementation function. Meant for Skylark usage.
1133 */
Francois-Rene Rideau95b0d0c2015-04-22 16:52:13 +00001134 public Builder setConfiguredTargetFunction(BaseFunction func) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001135 this.configuredTargetFunction = func;
1136 return this;
1137 }
1138
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001139 public Builder setExternalBindingsFunction(Function<? super Rule, Map<String, Label>> func) {
1140 this.externalBindingsFunction = func;
1141 return this;
1142 }
1143
janakrd3fe5e72018-03-30 12:49:12 -07001144 /** Sets the rule definition environment label and hash code. Meant for Skylark usage. */
1145 public Builder setRuleDefinitionEnvironmentLabelAndHashCode(Label label, String hashCode) {
1146 this.ruleDefinitionEnvironmentLabel = Preconditions.checkNotNull(label, this.name);
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001147 this.ruleDefinitionEnvironmentHashCode = Preconditions.checkNotNull(hashCode, this.name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001148 return this;
1149 }
1150
1151 /**
1152 * Removes an attribute with the same name from this rule class.
1153 *
1154 * @throws IllegalArgumentException if the attribute with this name does
1155 * not exist
1156 */
1157 public <TYPE> Builder removeAttribute(String name) {
1158 Preconditions.checkState(attributes.containsKey(name), "No such attribute '%s' to remove.",
1159 name);
1160 attributes.remove(name);
1161 return this;
1162 }
1163
1164 /**
1165 * This rule class outputs a default executable for every rule with the same name as
1166 * the rules's. Only works for Skylark.
1167 */
dslomov2ce98442017-10-23 19:14:02 +02001168 public <TYPE> Builder setExecutableSkylark() {
1169 this.isExecutableSkylark = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001170 return this;
1171 }
1172
cparsons55781c92018-10-17 12:03:08 -07001173 /** This rule class is marked as an analysis test. */
1174 public Builder setIsAnalysisTest() {
1175 this.isAnalysisTest = true;
1176 return this;
1177 }
1178
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001179 /**
Googlerc2200fd2018-09-14 17:35:59 -07001180 * This rule class has the _whitelist_function_transition attribute. Intended only for Skylark
1181 * rules.
1182 */
1183 public <TYPE> Builder setHasFunctionTransitionWhitelist() {
1184 this.hasFunctionTransitionWhitelist = true;
1185 return this;
1186 }
1187
1188 /**
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07001189 * Sets the kind of output files this rule creates.
1190 * DO NOT USE! This only exists to support the non-open-sourced {@code fileset} rule.
1191 * {@see OutputFile.Kind}.
1192 */
1193 public Builder setOutputFileKind(OutputFile.Kind outputFileKind) {
1194 this.outputFileKind = outputFileKind;
1195 return this;
1196 }
1197
1198
1199
1200 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001201 * Declares that instances of this rule are compatible with the specified environments,
1202 * in addition to the defaults declared by their environment groups. This can be overridden
1203 * by rule-specific declarations. See
1204 * {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for details.
1205 */
1206 public <TYPE> Builder compatibleWith(Label... environments) {
gregce614dc502017-12-20 17:24:46 -08001207 add(
1208 attr(DEFAULT_COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
1209 .value(ImmutableList.copyOf(environments)));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001210 return this;
1211 }
1212
1213 /**
1214 * Declares that instances of this rule are restricted to the specified environments, i.e.
1215 * these override the defaults declared by their environment groups. This can be overridden
1216 * by rule-specific declarations. See
1217 * {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for details.
1218 *
1219 * <p>The input list cannot be empty.
1220 */
1221 public <TYPE> Builder restrictedTo(Label firstEnvironment, Label... otherEnvironments) {
1222 ImmutableList<Label> environments = ImmutableList.<Label>builder().add(firstEnvironment)
1223 .add(otherEnvironments).build();
gregce614dc502017-12-20 17:24:46 -08001224 add(
1225 attr(DEFAULT_RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
1226 .value(environments));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001227 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001228 }
1229
1230 /**
Greg Estrenc04c88f2015-03-06 19:45:50 +00001231 * Exempts rules of this type from the constraint enforcement system. This should only be
1232 * applied to rules that are intrinsically incompatible with constraint checking (any
1233 * application of this method weakens the reach and strength of the system).
1234 *
1235 * @param reason user-informative message explaining the reason for exemption (not used)
1236 */
1237 public <TYPE> Builder exemptFromConstraintChecking(String reason) {
1238 Preconditions.checkState(this.supportsConstraintChecking);
1239 this.supportsConstraintChecking = false;
Greg Estren2ffc4fe2015-06-02 19:40:41 +00001240 attributes.remove(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR);
1241 attributes.remove(RuleClass.RESTRICTED_ENVIRONMENT_ATTR);
Greg Estrenc04c88f2015-03-06 19:45:50 +00001242 return this;
1243 }
1244
1245 /**
mstaibdf229582017-03-31 21:50:46 +00001246 * Causes rules of this type to be evaluated with the parent's configuration, always, so that
1247 * rules which match against parts of the configuration will behave as expected.
1248 *
1249 * <p>This is only intended for use by {@code config_setting} - other rules should not use this!
1250 */
1251 public Builder setIsConfigMatcherForConfigSettingOnly() {
1252 this.isConfigMatcher = true;
1253 return this;
1254 }
1255
1256 /**
mstaibe5538ad2017-04-04 18:32:23 +00001257 * Causes rules of this type to implicitly reference the configuration fragments associated with
1258 * the options its attributes reference.
1259 *
1260 * <p>This is only intended for use by {@code config_setting} - other rules should not use this!
1261 */
1262 public Builder setOptionReferenceFunctionForConfigSettingOnly(
1263 Function<? super Rule, ? extends Set<String>> optionReferenceFunction) {
1264 this.optionReferenceFunction = Preconditions.checkNotNull(optionReferenceFunction);
1265 return this;
1266 }
1267
John Cateree45c662018-06-05 11:09:01 -07001268 /**
1269 * Causes rules of this type to require the specified toolchains be available via toolchain
1270 * resolution when a target is configured.
1271 */
John Cater9a8d16e2017-07-05 16:12:07 -04001272 public Builder addRequiredToolchains(Iterable<Label> toolchainLabels) {
1273 Iterables.addAll(this.requiredToolchains, toolchainLabels);
John Catereca28402017-05-17 21:44:12 +02001274 return this;
1275 }
1276
John Cateree45c662018-06-05 11:09:01 -07001277 /**
1278 * Causes rules of this type to require the specified toolchains be available via toolchain
1279 * resolution when a target is configured.
1280 */
cpeyserd852e482017-09-07 22:16:06 +02001281 public Builder addRequiredToolchains(Label... toolchainLabels) {
John Cateree45c662018-06-05 11:09:01 -07001282 return this.addRequiredToolchains(Lists.newArrayList(toolchainLabels));
1283 }
1284
1285 /**
1286 * Rules that support platforms can use toolchains and execution platforms. Rules that are part
1287 * of configuring toolchains and platforms should set this to {@code false}.
1288 */
1289 public Builder supportsPlatforms(boolean flag) {
1290 this.supportsPlatforms = flag;
cpeyserd852e482017-09-07 22:16:06 +02001291 return this;
1292 }
1293
John Cateree45c662018-06-05 11:09:01 -07001294 /**
1295 * Specifies whether targets of this rule can add additional constraints on the execution
1296 * platform selected. If this is {@link ExecutionPlatformConstraintsAllowed#PER_TARGET}, there
1297 * will be an attribute named {@code exec_compatible_with} that can be used to add these
1298 * constraints.
1299 *
1300 * <p>Please note that this value is not inherited by child rules, and must be re-set on them if
1301 * the same behavior is required.
1302 */
1303 public Builder executionPlatformConstraintsAllowed(ExecutionPlatformConstraintsAllowed value) {
1304 this.executionPlatformConstraintsAllowed = value;
1305 return this;
1306 }
1307
1308 /**
1309 * Adds additional execution platform constraints that apply for all targets from this rule.
1310 *
1311 * <p>Please note that this value is inherited by child rules.
1312 */
1313 public Builder addExecutionPlatformConstraints(Label... constraints) {
1314 return this.addExecutionPlatformConstraints(Lists.newArrayList(constraints));
1315 }
1316
1317 /**
1318 * Adds additional execution platform constraints that apply for all targets from this rule.
1319 *
1320 * <p>Please note that this value is inherited by child rules.
1321 */
1322 public Builder addExecutionPlatformConstraints(Iterable<Label> constraints) {
1323 Iterables.addAll(this.executionPlatformConstraints, constraints);
John Cater856b4dd2017-11-21 08:06:16 -08001324 return this;
1325 }
1326
mstaibe5538ad2017-04-04 18:32:23 +00001327 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001328 * Returns an Attribute.Builder object which contains a replica of the
1329 * same attribute in the parent rule if exists.
1330 *
1331 * @param name the name of the attribute
1332 */
1333 public Attribute.Builder<?> copy(String name) {
1334 Preconditions.checkArgument(attributes.containsKey(name),
1335 "Attribute %s does not exist in parent rule class.", name);
1336 return attributes.get(name).cloneBuilder();
1337 }
1338 }
1339
1340 private final String name; // e.g. "cc_library"
1341
tomlu72642a22017-10-18 06:23:14 +02001342 private final String key; // Just the name for native, label + name for skylark
1343
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001344 /**
1345 * The kind of target represented by this RuleClass (e.g. "cc_library rule").
1346 * Note: Even though there is partial duplication with the {@link RuleClass#name} field,
1347 * we want to store this as a separate field instead of generating it on demand in order to
1348 * avoid string duplication.
1349 */
1350 private final String targetKind;
1351
janakr6ff110e2018-03-21 21:44:27 -07001352 private final RuleClassType type;
Michajlo Matijkiwbc042c62015-10-29 13:22:52 +00001353 private final boolean isSkylark;
Jon Brandveinead58ae2016-09-29 18:41:10 +00001354 private final boolean skylarkTestable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001355 private final boolean documented;
1356 private final boolean publicByDefault;
1357 private final boolean binaryOutput;
1358 private final boolean workspaceOnly;
dslomov2ce98442017-10-23 19:14:02 +02001359 private final boolean isExecutableSkylark;
cparsons55781c92018-10-17 12:03:08 -07001360 private final boolean isAnalysisTest;
mstaibdf229582017-03-31 21:50:46 +00001361 private final boolean isConfigMatcher;
Googlerc2200fd2018-09-14 17:35:59 -07001362 private final boolean hasFunctionTransitionWhitelist;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001363
1364 /**
1365 * A (unordered) mapping from attribute names to small integers indexing into
1366 * the {@code attributes} array.
1367 */
Miguel Alcon Pintod7795f42015-10-23 21:55:52 +00001368 private final Map<String, Integer> attributeIndex;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001369
1370 /**
1371 * All attributes of this rule class (including inherited ones) ordered by
1372 * attributeIndex value.
1373 */
Eric Fellheimera954fae2015-08-27 19:37:52 +00001374 private final ImmutableList<Attribute> attributes;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001375
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001376 /** Names of the non-configurable attributes of this rule class. */
1377 private final ImmutableList<String> nonConfigurableAttributes;
1378
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001379 /**
1380 * The set of implicit outputs generated by a rule, expressed as a function
1381 * of that rule.
1382 */
1383 private final ImplicitOutputsFunction implicitOutputsFunction;
1384
1385 /**
Michael Staib2a675202017-03-20 18:06:48 +00001386 * A factory which will produce a configuration transition that should be applied on any edge of
1387 * the configured target graph that leads into a target of this rule class.
Cal Peyser19dda252017-01-11 23:37:05 +00001388 */
Michael Staib2a675202017-03-20 18:06:48 +00001389 private final RuleTransitionFactory transitionFactory;
Cal Peyser19dda252017-01-11 23:37:05 +00001390
cparsonse2d200f2018-03-06 16:15:11 -08001391 /** The factory that creates configured targets from this rule. */
1392 private final ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001393
1394 /**
1395 * The constraint the package name of the rule instance must fulfill
1396 */
1397 private final PredicateWithMessage<Rule> validityPredicate;
1398
1399 /**
1400 * See {@link #isPreferredDependency}.
1401 */
1402 private final Predicate<String> preferredDependencyPredicate;
1403
1404 /**
1405 * The list of transitive info providers this class advertises to aspects.
1406 */
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001407 private final AdvertisedProviderSet advertisedProviders;
Lukacs Berki549bfce2016-04-22 15:29:12 +00001408
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001409 /**
1410 * The Skylark rule implementation of this RuleClass. Null for non Skylark executable RuleClasses.
1411 */
Francois-Rene Rideau95b0d0c2015-04-22 16:52:13 +00001412 @Nullable private final BaseFunction configuredTargetFunction;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001413
1414 /**
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001415 * Returns the extra bindings a workspace function adds to the WORKSPACE file.
1416 */
1417 private final Function<? super Rule, Map<String, Label>> externalBindingsFunction;
1418
1419 /**
mstaibe5538ad2017-04-04 18:32:23 +00001420 * Returns the options referenced by this rule's attributes.
1421 */
1422 private final Function<? super Rule, ? extends Set<String>> optionReferenceFunction;
1423
1424 /**
janakrd3fe5e72018-03-30 12:49:12 -07001425 * The Skylark rule definition environment's label and hash code of this RuleClass. Null for non
1426 * Skylark executable RuleClasses.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001427 */
janakrd3fe5e72018-03-30 12:49:12 -07001428 @Nullable private final Label ruleDefinitionEnvironmentLabel;
1429
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001430 @Nullable private final String ruleDefinitionEnvironmentHashCode;
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07001431 private final OutputFile.Kind outputFileKind;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001432
1433 /**
Michael Staibb51251e2015-09-29 23:31:51 +00001434 * The set of configuration fragments which are legal for this rule's implementation to access.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001435 */
Michael Staibb51251e2015-09-29 23:31:51 +00001436 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
Greg Estrenc04c88f2015-03-06 19:45:50 +00001437
1438 /**
1439 * Determines whether instances of this rule should be checked for constraint compatibility
1440 * with their dependencies and the rules that depend on them. This should be true for
1441 * everything except for rules that are intrinsically incompatible with the constraint system.
1442 */
1443 private final boolean supportsConstraintChecking;
1444
cpeyserfb829992017-09-07 17:17:03 +02001445 private final ImmutableSet<Label> requiredToolchains;
John Cater856b4dd2017-11-21 08:06:16 -08001446 private final boolean supportsPlatforms;
John Cateree45c662018-06-05 11:09:01 -07001447 private final ExecutionPlatformConstraintsAllowed executionPlatformConstraintsAllowed;
1448 private final ImmutableSet<Label> executionPlatformConstraints;
John Catereca28402017-05-17 21:44:12 +02001449
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001450 /**
John Catereca28402017-05-17 21:44:12 +02001451 * Constructs an instance of RuleClass whose name is 'name', attributes are 'attributes'. The
1452 * {@code srcsAllowedFiles} determines which types of files are allowed as parameters to the
1453 * "srcs" attribute; rules are always allowed. For the "deps" attribute, there are four cases:
1454 *
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001455 * <ul>
John Catereca28402017-05-17 21:44:12 +02001456 * <li>if the parameter is a file, it is allowed if its file type is given in {@code
1457 * depsAllowedFiles},
1458 * <li>if the parameter is a rule and the rule class is accepted by {@code depsAllowedRules},
1459 * then it is allowed,
1460 * <li>if the parameter is a rule and the rule class is not accepted by {@code
1461 * depsAllowedRules}, but accepted by {@code depsAllowedRulesWithWarning}, then it is
1462 * allowed, but triggers a warning;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001463 * <li>all other parameters trigger an error.
1464 * </ul>
1465 *
John Catereca28402017-05-17 21:44:12 +02001466 * <p>The {@code depsAllowedRules} predicate should have a {@code toString} method which returns a
1467 * plain English enumeration of the allowed rule class names, if it does not allow all rule
1468 * classes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001469 */
1470 @VisibleForTesting
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001471 RuleClass(
1472 String name,
tomlu72642a22017-10-18 06:23:14 +02001473 String key,
janakr6ff110e2018-03-21 21:44:27 -07001474 RuleClassType type,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001475 boolean isSkylark,
Jon Brandveinead58ae2016-09-29 18:41:10 +00001476 boolean skylarkTestable,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001477 boolean documented,
1478 boolean publicByDefault,
1479 boolean binaryOutput,
1480 boolean workspaceOnly,
dslomov2ce98442017-10-23 19:14:02 +02001481 boolean isExecutableSkylark,
cparsons55781c92018-10-17 12:03:08 -07001482 boolean isAnalysisTest,
Googlerc2200fd2018-09-14 17:35:59 -07001483 boolean hasFunctionTransitionWhitelist,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001484 ImplicitOutputsFunction implicitOutputsFunction,
mstaibdf229582017-03-31 21:50:46 +00001485 boolean isConfigMatcher,
Michael Staib2a675202017-03-20 18:06:48 +00001486 RuleTransitionFactory transitionFactory,
cparsonse2d200f2018-03-06 16:15:11 -08001487 ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001488 PredicateWithMessage<Rule> validityPredicate,
1489 Predicate<String> preferredDependencyPredicate,
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001490 AdvertisedProviderSet advertisedProviders,
Francois-Rene Rideau95b0d0c2015-04-22 16:52:13 +00001491 @Nullable BaseFunction configuredTargetFunction,
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001492 Function<? super Rule, Map<String, Label>> externalBindingsFunction,
mstaibe5538ad2017-04-04 18:32:23 +00001493 Function<? super Rule, ? extends Set<String>> optionReferenceFunction,
janakrd3fe5e72018-03-30 12:49:12 -07001494 @Nullable Label ruleDefinitionEnvironmentLabel,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001495 String ruleDefinitionEnvironmentHashCode,
Michael Staibb51251e2015-09-29 23:31:51 +00001496 ConfigurationFragmentPolicy configurationFragmentPolicy,
Greg Estrenc04c88f2015-03-06 19:45:50 +00001497 boolean supportsConstraintChecking,
cpeyserfb829992017-09-07 17:17:03 +02001498 Set<Label> requiredToolchains,
John Cater856b4dd2017-11-21 08:06:16 -08001499 boolean supportsPlatforms,
John Cateree45c662018-06-05 11:09:01 -07001500 ExecutionPlatformConstraintsAllowed executionPlatformConstraintsAllowed,
1501 Set<Label> executionPlatformConstraints,
cparsons55781c92018-10-17 12:03:08 -07001502 OutputFile.Kind outputFileKind,
janakrd3fe5e72018-03-30 12:49:12 -07001503 Collection<Attribute> attributes) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001504 this.name = name;
tomlu72642a22017-10-18 06:23:14 +02001505 this.key = key;
janakr6ff110e2018-03-21 21:44:27 -07001506 this.type = type;
Michajlo Matijkiwbc042c62015-10-29 13:22:52 +00001507 this.isSkylark = isSkylark;
Googlerb448eef2017-05-02 21:50:24 +02001508 this.targetKind = name + Rule.targetKindSuffix();
Jon Brandveinead58ae2016-09-29 18:41:10 +00001509 this.skylarkTestable = skylarkTestable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001510 this.documented = documented;
1511 this.publicByDefault = publicByDefault;
1512 this.binaryOutput = binaryOutput;
1513 this.implicitOutputsFunction = implicitOutputsFunction;
mstaibdf229582017-03-31 21:50:46 +00001514 this.isConfigMatcher = isConfigMatcher;
Michael Staib2a675202017-03-20 18:06:48 +00001515 this.transitionFactory = transitionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001516 this.configuredTargetFactory = configuredTargetFactory;
1517 this.validityPredicate = validityPredicate;
1518 this.preferredDependencyPredicate = preferredDependencyPredicate;
1519 this.advertisedProviders = advertisedProviders;
1520 this.configuredTargetFunction = configuredTargetFunction;
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001521 this.externalBindingsFunction = externalBindingsFunction;
mstaibe5538ad2017-04-04 18:32:23 +00001522 this.optionReferenceFunction = optionReferenceFunction;
janakrd3fe5e72018-03-30 12:49:12 -07001523 this.ruleDefinitionEnvironmentLabel = ruleDefinitionEnvironmentLabel;
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001524 this.ruleDefinitionEnvironmentHashCode = ruleDefinitionEnvironmentHashCode;
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07001525 this.outputFileKind = outputFileKind;
Dmitry Lomov94387c22015-12-08 16:30:06 +00001526 validateNoClashInPublicNames(attributes);
Eric Fellheimera954fae2015-08-27 19:37:52 +00001527 this.attributes = ImmutableList.copyOf(attributes);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001528 this.workspaceOnly = workspaceOnly;
dslomov2ce98442017-10-23 19:14:02 +02001529 this.isExecutableSkylark = isExecutableSkylark;
cparsons55781c92018-10-17 12:03:08 -07001530 this.isAnalysisTest = isAnalysisTest;
Googlerc2200fd2018-09-14 17:35:59 -07001531 this.hasFunctionTransitionWhitelist = hasFunctionTransitionWhitelist;
Michael Staibb51251e2015-09-29 23:31:51 +00001532 this.configurationFragmentPolicy = configurationFragmentPolicy;
Greg Estrenc04c88f2015-03-06 19:45:50 +00001533 this.supportsConstraintChecking = supportsConstraintChecking;
cpeyserfb829992017-09-07 17:17:03 +02001534 this.requiredToolchains = ImmutableSet.copyOf(requiredToolchains);
John Cater856b4dd2017-11-21 08:06:16 -08001535 this.supportsPlatforms = supportsPlatforms;
John Cateree45c662018-06-05 11:09:01 -07001536 this.executionPlatformConstraintsAllowed = executionPlatformConstraintsAllowed;
1537 this.executionPlatformConstraints = ImmutableSet.copyOf(executionPlatformConstraints);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001538
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001539 // Create the index and collect non-configurable attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001540 int index = 0;
janakrd3fe5e72018-03-30 12:49:12 -07001541 attributeIndex = new HashMap<>(attributes.size());
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001542 ImmutableList.Builder<String> nonConfigurableAttributesBuilder = ImmutableList.builder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001543 for (Attribute attribute : attributes) {
1544 attributeIndex.put(attribute.getName(), index++);
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001545 if (!attribute.isConfigurable()) {
1546 nonConfigurableAttributesBuilder.add(attribute.getName());
1547 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001548 }
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001549 this.nonConfigurableAttributes = nonConfigurableAttributesBuilder.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001550 }
1551
janakrd3fe5e72018-03-30 12:49:12 -07001552 private void validateNoClashInPublicNames(Iterable<Attribute> attributes) {
Dmitry Lomov94387c22015-12-08 16:30:06 +00001553 Map<String, Attribute> publicToPrivateNames = new HashMap<>();
1554 for (Attribute attribute : attributes) {
1555 String publicName = attribute.getPublicName();
1556 if (publicToPrivateNames.containsKey(publicName)) {
1557 throw new IllegalStateException(
1558 String.format(
1559 "Rule %s: Attributes %s and %s have an identical public name: %s",
1560 name,
1561 attribute.getName(),
1562 publicToPrivateNames.get(publicName).getName(),
1563 publicName));
1564 }
1565 publicToPrivateNames.put(publicName, attribute);
1566 }
1567 }
1568
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001569 /**
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001570 * Returns the default function for determining the set of implicit outputs generated by a given
1571 * rule. If not otherwise specified, this will be the implementation used by {@link Rule}s
1572 * created with this {@link RuleClass}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001573 *
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001574 * <p>Do not use this value to calculate implicit outputs for a rule, instead use
1575 * {@link Rule#getImplicitOutputsFunction()}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001576 *
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001577 * <p>An implicit output is an OutputFile that automatically comes into existence when a rule of
1578 * this class is declared, and whose name is derived from the name of the rule.
1579 *
1580 * <p>Implicit outputs are a widely-relied upon. All ".so", and "_deploy.jar" targets referenced
1581 * in BUILD files are examples.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001582 */
1583 @VisibleForTesting
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001584 public ImplicitOutputsFunction getDefaultImplicitOutputsFunction() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001585 return implicitOutputsFunction;
1586 }
1587
Michael Staib2a675202017-03-20 18:06:48 +00001588 public RuleTransitionFactory getTransitionFactory() {
1589 return transitionFactory;
Cal Peyser19dda252017-01-11 23:37:05 +00001590 }
1591
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001592 @SuppressWarnings("unchecked")
cparsonse2d200f2018-03-06 16:15:11 -08001593 public <CT, RC, ACE extends Throwable>
1594 ConfiguredTargetFactory<CT, RC, ACE> getConfiguredTargetFactory() {
1595 return (ConfiguredTargetFactory<CT, RC, ACE>) configuredTargetFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001596 }
1597
1598 /**
1599 * Returns the class of rule that this RuleClass represents (e.g. "cc_library").
1600 */
1601 public String getName() {
1602 return name;
1603 }
1604
janakr6ff110e2018-03-21 21:44:27 -07001605 /** Returns the type of rule that this RuleClass represents. Only for use during serialization. */
1606 public RuleClassType getRuleClassType() {
1607 return type;
1608 }
1609
tomlu72642a22017-10-18 06:23:14 +02001610 /** Returns a unique key. Used for profiling purposes. */
1611 public String getKey() {
1612 return key;
1613 }
1614
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001615 /**
1616 * Returns the target kind of this class of rule (e.g. "cc_library rule").
1617 */
1618 String getTargetKind() {
1619 return targetKind;
1620 }
1621
1622 public boolean getWorkspaceOnly() {
1623 return workspaceOnly;
1624 }
1625
1626 /**
1627 * Returns true iff the attribute 'attrName' is defined for this rule class,
1628 * and has type 'type'.
1629 */
1630 public boolean hasAttr(String attrName, Type<?> type) {
1631 Integer index = getAttributeIndex(attrName);
1632 return index != null && getAttribute(index).getType() == type;
1633 }
1634
1635 /**
1636 * Returns the index of the specified attribute name. Use of indices allows
1637 * space-efficient storage of attribute values in rules, since hashtables are
1638 * not required. (The index mapping is specific to each RuleClass and an
1639 * attribute may have a different index in the parent RuleClass.)
1640 *
1641 * <p>Returns null if the named attribute is not defined for this class of Rule.
1642 */
1643 Integer getAttributeIndex(String attrName) {
1644 return attributeIndex.get(attrName);
1645 }
1646
1647 /**
1648 * Returns the attribute whose index is 'attrIndex'. Fails if attrIndex is
1649 * not in range.
1650 */
1651 Attribute getAttribute(int attrIndex) {
Eric Fellheimera954fae2015-08-27 19:37:52 +00001652 return attributes.get(attrIndex);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001653 }
1654
1655 /**
Michajlo Matijkiw0446c952015-10-28 19:59:00 +00001656 * Returns the attribute whose name is 'attrName'; fails with NullPointerException if not found.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001657 */
1658 public Attribute getAttributeByName(String attrName) {
Michajlo Matijkiw0446c952015-10-28 19:59:00 +00001659 Integer attrIndex = Preconditions.checkNotNull(getAttributeIndex(attrName),
1660 "Attribute %s does not exist", attrName);
1661 return attributes.get(attrIndex);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001662 }
1663
1664 /**
1665 * Returns the attribute whose name is {@code attrName}, or null if not
1666 * found.
1667 */
1668 Attribute getAttributeByNameMaybe(String attrName) {
1669 Integer i = getAttributeIndex(attrName);
Eric Fellheimera954fae2015-08-27 19:37:52 +00001670 return i == null ? null : attributes.get(i);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001671 }
1672
1673 /**
1674 * Returns the number of attributes defined for this rule class.
1675 */
1676 public int getAttributeCount() {
1677 return attributeIndex.size();
1678 }
1679
1680 /**
1681 * Returns an (immutable) list of all Attributes defined for this class of
1682 * rule, ordered by increasing index.
1683 */
1684 public List<Attribute> getAttributes() {
Eric Fellheimera954fae2015-08-27 19:37:52 +00001685 return attributes;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001686 }
1687
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001688 /** Returns set of non-configurable attribute names defined for this class of rule. */
1689 public List<String> getNonConfigurableAttributes() {
1690 return nonConfigurableAttributes;
1691 }
1692
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001693 public PredicateWithMessage<Rule> getValidityPredicate() {
1694 return validityPredicate;
1695 }
1696
1697 /**
1698 * Returns the set of advertised transitive info providers.
1699 *
1700 * <p>When computing the set of aspects required for a rule, only the providers listed here are
1701 * considered. The presence of a provider here does not mean that the rule <b>must</b> implement
1702 * said provider, merely that it <b>can</b>. After the configured target is constructed from this
1703 * rule, aspects will be filtered according to the set of actual providers.
1704 *
1705 * <p>This is here so that we can do the loading phase overestimation required for "blaze query",
1706 * which does not have the configured targets available.
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001707 **/
1708 public AdvertisedProviderSet getAdvertisedProviders() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001709 return advertisedProviders;
1710 }
Lukacs Berki549bfce2016-04-22 15:29:12 +00001711 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001712 * For --compile_one_dependency: if multiple rules consume the specified target,
1713 * should we choose this one over the "unpreferred" options?
1714 */
1715 public boolean isPreferredDependency(String filename) {
1716 return preferredDependencyPredicate.apply(filename);
1717 }
1718
1719 /**
Michael Staibb51251e2015-09-29 23:31:51 +00001720 * Returns this rule's policy for configuration fragment access.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001721 */
Michael Staibb51251e2015-09-29 23:31:51 +00001722 public ConfigurationFragmentPolicy getConfigurationFragmentPolicy() {
1723 return configurationFragmentPolicy;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001724 }
1725
1726 /**
Greg Estrenc04c88f2015-03-06 19:45:50 +00001727 * Returns true if rules of this type can be used with the constraint enforcement system.
1728 */
1729 public boolean supportsConstraintChecking() {
1730 return supportsConstraintChecking;
1731 }
1732
1733 /**
mstaibdf229582017-03-31 21:50:46 +00001734 * Returns true if rules of this type should be evaluated with the parent's configuration so that
1735 * they can match on aspects of it.
1736 */
1737 public boolean isConfigMatcher() {
1738 return isConfigMatcher;
1739 }
1740
1741 /**
Mark Schalleree624452016-01-13 18:41:24 +00001742 * Creates a new {@link Rule} {@code r} where {@code r.getPackage()} is the {@link Package}
1743 * associated with {@code pkgBuilder}.
1744 *
1745 * <p>The created {@link Rule} will be populated with attribute values from {@code
1746 * attributeValues} or the default attribute values associated with this {@link RuleClass} and
1747 * {@code pkgBuilder}.
1748 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001749 * <p>The created {@link Rule} will also be populated with output files. These output files will
1750 * have been collected from the explicitly provided values of type {@link BuildType#OUTPUT} and
1751 * {@link BuildType#OUTPUT_LIST} as well as from the implicit outputs determined by this {@link
1752 * RuleClass} and the values in {@code attributeValues}.
Mark Schalleree624452016-01-13 18:41:24 +00001753 *
1754 * <p>This performs several validity checks. Invalid output file labels result in a thrown {@link
Florian Weikertea6c82d2016-09-05 12:15:31 +00001755 * LabelSyntaxException}. Computed default attributes that fail during precomputation result in a
1756 * {@link CannotPrecomputeDefaultsException}. All other errors are reported on {@code
1757 * eventHandler}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001758 */
nharmata65a173a2017-08-07 16:11:04 +02001759 <T> Rule createRule(
Mark Schalleree624452016-01-13 18:41:24 +00001760 Package.Builder pkgBuilder,
1761 Label ruleLabel,
nharmata65a173a2017-08-07 16:11:04 +02001762 AttributeValues<T> attributeValues,
Mark Schalleree624452016-01-13 18:41:24 +00001763 EventHandler eventHandler,
1764 @Nullable FuncallExpression ast,
1765 Location location,
1766 AttributeContainer attributeContainer)
Florian Weikertea6c82d2016-09-05 12:15:31 +00001767 throws LabelSyntaxException, InterruptedException, CannotPrecomputeDefaultsException {
Michajlo Matijkiw581f2c22016-07-25 20:12:16 +00001768 Rule rule = pkgBuilder.createRule(ruleLabel, this, location, attributeContainer);
1769 populateRuleAttributeValues(rule, pkgBuilder, attributeValues, eventHandler);
1770 checkAspectAllowedValues(rule, eventHandler);
1771 rule.populateOutputFiles(eventHandler, pkgBuilder);
1772 if (ast != null) {
1773 populateAttributeLocations(rule, ast);
1774 }
1775 checkForDuplicateLabels(rule, eventHandler);
1776 checkThirdPartyRuleHasLicense(rule, pkgBuilder, eventHandler);
1777 checkForValidSizeAndTimeoutValues(rule, eventHandler);
1778 rule.checkValidityPredicate(eventHandler);
Nathan Harmatacf738442016-06-28 14:52:21 +00001779 rule.checkForNullLabels();
1780 return rule;
1781 }
1782
1783 /**
1784 * Same as {@link #createRule}, except without some internal sanity checks.
1785 *
1786 * <p>Don't call this function unless you know what you're doing.
1787 */
nharmata65a173a2017-08-07 16:11:04 +02001788 <T> Rule createRuleUnchecked(
Nathan Harmatacf738442016-06-28 14:52:21 +00001789 Package.Builder pkgBuilder,
1790 Label ruleLabel,
nharmata65a173a2017-08-07 16:11:04 +02001791 AttributeValues<T> attributeValues,
Nathan Harmatacf738442016-06-28 14:52:21 +00001792 Location location,
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001793 AttributeContainer attributeContainer,
1794 ImplicitOutputsFunction implicitOutputsFunction)
nharmata59c16f62017-08-07 19:49:09 +02001795 throws InterruptedException, CannotPrecomputeDefaultsException {
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001796 Rule rule = pkgBuilder.createRule(
1797 ruleLabel,
1798 this,
1799 location,
1800 attributeContainer,
1801 implicitOutputsFunction);
Michajlo Matijkiw581f2c22016-07-25 20:12:16 +00001802 populateRuleAttributeValues(rule, pkgBuilder, attributeValues, NullEventHandler.INSTANCE);
nharmata59c16f62017-08-07 19:49:09 +02001803 rule.populateOutputFilesUnchecked(NullEventHandler.INSTANCE, pkgBuilder);
Mark Schalleree624452016-01-13 18:41:24 +00001804 return rule;
1805 }
1806
1807 /**
1808 * Populates the attributes table of the new {@link Rule} with the values in the {@code
1809 * attributeValues} map and with default values provided by this {@link RuleClass} and the {@code
1810 * pkgBuilder}.
1811 *
1812 * <p>Errors are reported on {@code eventHandler}.
1813 */
nharmata65a173a2017-08-07 16:11:04 +02001814 private <T> void populateRuleAttributeValues(
Mark Schalleree624452016-01-13 18:41:24 +00001815 Rule rule,
1816 Package.Builder pkgBuilder,
nharmata65a173a2017-08-07 16:11:04 +02001817 AttributeValues<T> attributeValues,
Florian Weikertea6c82d2016-09-05 12:15:31 +00001818 EventHandler eventHandler)
1819 throws InterruptedException, CannotPrecomputeDefaultsException {
Mark Schalleree624452016-01-13 18:41:24 +00001820 BitSet definedAttrIndices =
dannarkf24479d2018-06-21 11:55:44 -07001821 populateDefinedRuleAttributeValues(
1822 rule, pkgBuilder.getRepositoryMapping(), attributeValues, eventHandler);
Mark Schalleree624452016-01-13 18:41:24 +00001823 populateDefaultRuleAttributeValues(rule, pkgBuilder, definedAttrIndices, eventHandler);
1824 // Now that all attributes are bound to values, collect and store configurable attribute keys.
1825 populateConfigDependenciesAttribute(rule);
1826 }
1827
1828 /**
1829 * Populates the attributes table of the new {@link Rule} with the values in the {@code
1830 * attributeValues} map.
1831 *
1832 * <p>Handles the special cases of the attribute named {@code "name"} and attributes with value
1833 * {@link Runtime#NONE}.
1834 *
dannarkf24479d2018-06-21 11:55:44 -07001835 * <p>Returns a bitset {@code b} where {@code b.get(i)} is {@code true} if this method set a value
1836 * for the attribute with index {@code i} in this {@link RuleClass}. Errors are reported on {@code
1837 * eventHandler}.
Mark Schalleree624452016-01-13 18:41:24 +00001838 */
nharmata65a173a2017-08-07 16:11:04 +02001839 private <T> BitSet populateDefinedRuleAttributeValues(
dannarkf24479d2018-06-21 11:55:44 -07001840 Rule rule,
1841 ImmutableMap<RepositoryName, RepositoryName> repositoryMapping,
1842 AttributeValues<T> attributeValues,
1843 EventHandler eventHandler) {
Mark Schalleree624452016-01-13 18:41:24 +00001844 BitSet definedAttrIndices = new BitSet();
nharmata65a173a2017-08-07 16:11:04 +02001845 for (T attributeAccessor : attributeValues.getAttributeAccessors()) {
1846 String attributeName = attributeValues.getName(attributeAccessor);
1847 Object attributeValue = attributeValues.getValue(attributeAccessor);
Mark Schalleree624452016-01-13 18:41:24 +00001848 // Ignore all None values.
1849 if (attributeValue == Runtime.NONE) {
1850 continue;
1851 }
1852
1853 // Check that the attribute's name belongs to a valid attribute for this rule class.
1854 Integer attrIndex = getAttributeIndex(attributeName);
1855 if (attrIndex == null) {
1856 rule.reportError(
1857 String.format(
1858 "%s: no such attribute '%s' in '%s' rule", rule.getLabel(), attributeName, name),
1859 eventHandler);
1860 continue;
1861 }
1862 Attribute attr = getAttribute(attrIndex);
1863
1864 // Convert the build-lang value to a native value, if necessary.
1865 Object nativeAttributeValue;
1866 if (attributeValues.valuesAreBuildLanguageTyped()) {
1867 try {
dannarkf24479d2018-06-21 11:55:44 -07001868 nativeAttributeValue =
1869 convertFromBuildLangType(rule, attr, attributeValue, repositoryMapping);
Mark Schalleree624452016-01-13 18:41:24 +00001870 } catch (ConversionException e) {
1871 rule.reportError(String.format("%s: %s", rule.getLabel(), e.getMessage()), eventHandler);
1872 continue;
1873 }
1874 } else {
1875 nativeAttributeValue = attributeValue;
1876 }
1877
nharmata65a173a2017-08-07 16:11:04 +02001878 boolean explicit = attributeValues.isExplicitlySpecified(attributeAccessor);
Mark Schalleree624452016-01-13 18:41:24 +00001879 setRuleAttributeValue(rule, eventHandler, attr, nativeAttributeValue, explicit);
1880 definedAttrIndices.set(attrIndex);
Mark Schalleree624452016-01-13 18:41:24 +00001881 }
1882 return definedAttrIndices;
1883 }
1884
1885 /** Populates attribute locations for attributes defined in {@code ast}. */
1886 private void populateAttributeLocations(Rule rule, FuncallExpression ast) {
1887 for (Argument.Passed arg : ast.getArguments()) {
1888 if (arg.isKeyword()) {
1889 String name = arg.getName();
1890 Integer attrIndex = getAttributeIndex(name);
1891 if (attrIndex != null) {
1892 rule.setAttributeLocation(attrIndex, arg.getValue().getLocation());
1893 }
1894 }
1895 }
1896 }
1897
1898 /**
1899 * Populates the attributes table of the new {@link Rule} with default values provided by this
Florian Weikertea6c82d2016-09-05 12:15:31 +00001900 * {@link RuleClass} and the {@code pkgBuilder}. This will only provide values for attributes that
1901 * haven't already been populated, using {@code definedAttrIndices} to determine whether an
Mark Schalleree624452016-01-13 18:41:24 +00001902 * attribute was populated.
1903 *
1904 * <p>Errors are reported on {@code eventHandler}.
1905 */
1906 private void populateDefaultRuleAttributeValues(
Florian Weikertea6c82d2016-09-05 12:15:31 +00001907 Rule rule, Package.Builder pkgBuilder, BitSet definedAttrIndices, EventHandler eventHandler)
1908 throws InterruptedException, CannotPrecomputeDefaultsException {
Mark Schalleree624452016-01-13 18:41:24 +00001909 // Set defaults; ensure that every mandatory attribute has a value. Use the default if none
1910 // is specified.
1911 List<Attribute> attrsWithComputedDefaults = new ArrayList<>();
1912 int numAttributes = getAttributeCount();
1913 for (int attrIndex = 0; attrIndex < numAttributes; ++attrIndex) {
1914 if (definedAttrIndices.get(attrIndex)) {
1915 continue;
1916 }
1917 Attribute attr = getAttribute(attrIndex);
1918 if (attr.isMandatory()) {
1919 rule.reportError(
1920 String.format(
1921 "%s: missing value for mandatory attribute '%s' in '%s' rule",
1922 rule.getLabel(),
1923 attr.getName(),
1924 name),
1925 eventHandler);
1926 }
1927
1928 if (attr.hasComputedDefault()) {
1929 // Note that it is necessary to set all non-computed default values before calling
1930 // Attribute#getDefaultValue for computed default attributes. Computed default attributes
1931 // may have a condition predicate (i.e. the predicate returned by Attribute#getCondition)
1932 // that depends on non-computed default attribute values, and that condition predicate is
1933 // evaluated by the call to Attribute#getDefaultValue.
1934 attrsWithComputedDefaults.add(attr);
cparsonscaceacd2017-11-04 01:00:59 +01001935 } else if (attr.isLateBound()) {
1936 rule.setAttributeValue(attr, attr.getLateBoundDefault(), /*explicit=*/ false);
Mark Schalleree624452016-01-13 18:41:24 +00001937 } else {
1938 Object defaultValue = getAttributeNoncomputedDefaultValue(attr, pkgBuilder);
Mark Schalleree624452016-01-13 18:41:24 +00001939 rule.setAttributeValue(attr, defaultValue, /*explicit=*/ false);
1940 checkAllowedValues(rule, attr, eventHandler);
1941 }
1942 }
1943
1944 // Set computed default attribute values now that all other (i.e. non-computed) default values
1945 // have been set.
1946 for (Attribute attr : attrsWithComputedDefaults) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001947 // If Attribute#hasComputedDefault was true above, Attribute#getDefaultValue returns the
1948 // computed default function object or a Skylark computed default template. Note that we
1949 // cannot determine the exact value of the computed default function here because it may
1950 // depend on other attribute values that are configurable (i.e. they came from select({..})
1951 // expressions in the build language, and they require configuration data from the analysis
1952 // phase to be resolved). Instead, we're setting the attribute value to a reference to the
1953 // computed default function, or if #getDefaultValue is a Skylark computed default
1954 // template, setting the attribute value to a reference to the SkylarkComputedDefault
1955 // returned from SkylarkComputedDefaultTemplate#computePossibleValues.
1956 //
1957 // SkylarkComputedDefaultTemplate#computePossibleValues pre-computes all possible values the
1958 // function may evaluate to, and records them in a lookup table. By calling it here, with an
1959 // EventHandler, any errors that might occur during the function's evaluation can
1960 // be discovered and propagated here.
1961 Object valueToSet;
1962 Object defaultValue = attr.getDefaultValue(rule);
1963 if (defaultValue instanceof SkylarkComputedDefaultTemplate) {
1964 SkylarkComputedDefaultTemplate template = (SkylarkComputedDefaultTemplate) defaultValue;
1965 valueToSet = template.computePossibleValues(attr, rule, eventHandler);
1966 } else {
1967 valueToSet = defaultValue;
1968 }
1969 rule.setAttributeValue(attr, valueToSet, /*explicit=*/ false);
Mark Schalleree624452016-01-13 18:41:24 +00001970 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001971 }
1972
1973 /**
1974 * Collects all labels used as keys for configurable attributes and places them into
1975 * the special implicit attribute that tracks them.
1976 */
1977 private static void populateConfigDependenciesAttribute(Rule rule) {
1978 RawAttributeMapper attributes = RawAttributeMapper.of(rule);
1979 Attribute configDepsAttribute = attributes.getAttributeDefinition("$config_dependencies");
1980 if (configDepsAttribute == null) {
1981 // Not currently compatible with Skylark rules.
1982 return;
1983 }
1984
1985 Set<Label> configLabels = new LinkedHashSet<>();
1986 for (Attribute attr : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00001987 SelectorList<?> selectors = attributes.getSelectorList(attr.getName(), attr.getType());
Greg Estrena4fc8772015-04-13 19:58:23 +00001988 if (selectors != null) {
Lukacs Berkia88755c2016-01-22 16:40:37 +00001989 configLabels.addAll(selectors.getKeyLabels());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001990 }
1991 }
1992
1993 rule.setAttributeValue(configDepsAttribute, ImmutableList.copyOf(configLabels),
1994 /*explicit=*/false);
1995 }
1996
Nathan Harmatafcb17112016-04-13 16:56:58 +00001997 public void checkAttributesNonEmpty(
michajloc1062a42018-09-26 14:53:38 -07001998 RuleErrorConsumer ruleErrorConsumer, AttributeMap attributes) {
Nathan Harmatafcb17112016-04-13 16:56:58 +00001999 for (String attributeName : attributes.getAttributeNames()) {
2000 Attribute attr = attributes.getAttributeDefinition(attributeName);
2001 if (!attr.isNonEmpty()) {
2002 continue;
2003 }
2004 Object attributeValue = attributes.get(attributeName, attr.getType());
Francois-Rene Rideau93ed7f12015-10-20 15:39:33 +00002005
Nathan Harmatafcb17112016-04-13 16:56:58 +00002006 boolean isEmpty = false;
2007 if (attributeValue instanceof SkylarkList) {
michajloc1062a42018-09-26 14:53:38 -07002008 isEmpty = ((SkylarkList<?>) attributeValue).isEmpty();
Nathan Harmatafcb17112016-04-13 16:56:58 +00002009 } else if (attributeValue instanceof List<?>) {
2010 isEmpty = ((List<?>) attributeValue).isEmpty();
2011 } else if (attributeValue instanceof Map<?, ?>) {
2012 isEmpty = ((Map<?, ?>) attributeValue).isEmpty();
2013 }
Francois-Rene Rideau5e00ec62015-10-20 17:02:19 +00002014
Nathan Harmatafcb17112016-04-13 16:56:58 +00002015 if (isEmpty) {
2016 ruleErrorConsumer.attributeError(attr.getName(), "attribute must be non empty");
2017 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002018 }
2019 }
2020
2021 /**
2022 * Report an error for each label that appears more than once in a LABEL_LIST attribute
2023 * of the given rule.
2024 *
2025 * @param rule The rule.
2026 * @param eventHandler The eventHandler to use to report the duplicated deps.
2027 */
2028 private static void checkForDuplicateLabels(Rule rule, EventHandler eventHandler) {
2029 for (Attribute attribute : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00002030 if (attribute.getType() == BuildType.LABEL_LIST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002031 checkForDuplicateLabels(rule, attribute, eventHandler);
2032 }
2033 }
2034 }
2035
2036 /**
2037 * Reports an error against the specified rule if it's beneath third_party
2038 * but does not have a declared license.
2039 */
2040 private static void checkThirdPartyRuleHasLicense(Rule rule,
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00002041 Package.Builder pkgBuilder, EventHandler eventHandler) {
Brian Silvermand7d6d622016-03-17 09:53:39 +00002042 if (isThirdPartyPackage(rule.getLabel().getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002043 License license = rule.getLicense();
2044 if (license == null) {
2045 license = pkgBuilder.getDefaultLicense();
2046 }
lberki0d8d4cf2017-09-05 16:01:44 +02002047 if (!license.isSpecified()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002048 rule.reportError("third-party rule '" + rule.getLabel() + "' lacks a license declaration "
2049 + "with one of the following types: notice, reciprocal, permissive, "
2050 + "restricted, unencumbered, by_exception_only",
2051 eventHandler);
2052 }
2053 }
2054 }
2055
2056 /**
2057 * Report an error for each label that appears more than once in the given attribute
2058 * of the given rule.
2059 *
2060 * @param rule The rule.
2061 * @param attribute The attribute to check. Must exist in rule and be of type LABEL_LIST.
2062 * @param eventHandler The eventHandler to use to report the duplicated deps.
2063 */
2064 private static void checkForDuplicateLabels(Rule rule, Attribute attribute,
2065 EventHandler eventHandler) {
Greg Estren14348c02015-04-16 16:26:19 +00002066 Set<Label> duplicates = AggregatingAttributeMapper.of(rule).checkForDuplicateLabels(attribute);
2067 for (Label label : duplicates) {
2068 rule.reportError(
2069 String.format("Label '%s' is duplicated in the '%s' attribute of rule '%s'",
2070 label, attribute.getName(), rule.getName()), eventHandler);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002071 }
2072 }
2073
2074 /**
2075 * Report an error if the rule has a timeout or size attribute that is not a
2076 * legal value. These attributes appear on all tests.
2077 *
2078 * @param rule the rule to check
2079 * @param eventHandler the eventHandler to use to report the duplicated deps
2080 */
2081 private static void checkForValidSizeAndTimeoutValues(Rule rule, EventHandler eventHandler) {
2082 if (rule.getRuleClassObject().hasAttr("size", Type.STRING)) {
2083 String size = NonconfigurableAttributeMapper.of(rule).get("size", Type.STRING);
2084 if (TestSize.getTestSize(size) == null) {
2085 rule.reportError(
2086 String.format("In rule '%s', size '%s' is not a valid size.", rule.getName(), size),
2087 eventHandler);
2088 }
2089 }
2090 if (rule.getRuleClassObject().hasAttr("timeout", Type.STRING)) {
2091 String timeout = NonconfigurableAttributeMapper.of(rule).get("timeout", Type.STRING);
2092 if (TestTimeout.getTestTimeout(timeout) == null) {
2093 rule.reportError(
2094 String.format(
2095 "In rule '%s', timeout '%s' is not a valid timeout.", rule.getName(), timeout),
2096 eventHandler);
2097 }
2098 }
2099 }
2100
2101 /**
2102 * Returns the default value for the specified rule attribute.
2103 *
Francois-Rene Rideau5dcdbf92015-02-19 18:36:17 +00002104 * <p>For most rule attributes, the default value is either explicitly specified
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002105 * in the attribute, or implicitly based on the type of the attribute, except
2106 * for some special cases (e.g. "licenses", "distribs") where it comes from
2107 * some other source, such as state in the package.
2108 *
Francois-Rene Rideau5dcdbf92015-02-19 18:36:17 +00002109 * <p>Precondition: {@code !attr.hasComputedDefault()}. (Computed defaults are
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002110 * evaluated in second pass.)
2111 */
2112 private static Object getAttributeNoncomputedDefaultValue(Attribute attr,
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00002113 Package.Builder pkgBuilder) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002114 if (attr.getName().equals("licenses")) {
2115 return pkgBuilder.getDefaultLicense();
2116 }
2117 if (attr.getName().equals("distribs")) {
2118 return pkgBuilder.getDefaultDistribs();
2119 }
2120 return attr.getDefaultValue(null);
2121 }
2122
2123 /**
Mark Schalleree624452016-01-13 18:41:24 +00002124 * Sets the value of attribute {@code attr} in {@code rule} to the native value {@code
2125 * nativeAttrVal}, and sets the value's explicitness to {@code explicit}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002126 *
Mark Schalleree624452016-01-13 18:41:24 +00002127 * <p>Handles the special case of the "visibility" attribute by also setting the rule's
2128 * visibility with {@link Rule#setVisibility}.
2129 *
2130 * <p>Checks that {@code nativeAttrVal} is an allowed value via {@link #checkAllowedValues}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002131 */
Mark Schalleree624452016-01-13 18:41:24 +00002132 private static void setRuleAttributeValue(
2133 Rule rule,
2134 EventHandler eventHandler,
2135 Attribute attr,
2136 Object nativeAttrVal,
2137 boolean explicit) {
2138 if (attr.getName().equals("visibility")) {
2139 @SuppressWarnings("unchecked")
2140 List<Label> attrList = (List<Label>) nativeAttrVal;
Francois-Rene Rideaucbebd632015-02-11 16:56:37 +00002141 if (!attrList.isEmpty()
2142 && ConstantRuleVisibility.LEGACY_PUBLIC_LABEL.equals(attrList.get(0))) {
Mark Schalleree624452016-01-13 18:41:24 +00002143 rule.reportError(
2144 rule.getLabel() + ": //visibility:legacy_public only allowed in package declaration",
2145 eventHandler);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002146 }
Yue Gan36a26572016-05-25 11:48:10 +00002147 try {
2148 rule.setVisibility(PackageFactory.getVisibility(rule.getLabel(), attrList));
2149 } catch (EvalException e) {
2150 rule.reportError(rule.getLabel() + " " + e.getMessage(), eventHandler);
2151 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002152 }
Mark Schalleree624452016-01-13 18:41:24 +00002153 rule.setAttributeValue(attr, nativeAttrVal, explicit);
Michael Staibff938b32015-08-27 19:22:59 +00002154 checkAllowedValues(rule, attr, eventHandler);
Mark Schalleree624452016-01-13 18:41:24 +00002155 }
2156
2157 /**
2158 * Converts the build-language-typed {@code buildLangValue} to a native value via {@link
laurentlb1d273cd2018-05-16 12:12:26 -07002159 * BuildType#selectableConvert}. Canonicalizes the value's order if it is a {@link List} type and
2160 * {@code attr.isOrderIndependent()} returns {@code true}.
Mark Schalleree624452016-01-13 18:41:24 +00002161 *
laurentlb1d273cd2018-05-16 12:12:26 -07002162 * <p>Throws {@link ConversionException} if the conversion fails, or if {@code buildLangValue} is
2163 * a selector expression but {@code attr.isConfigurable()} is {@code false}.
Mark Schalleree624452016-01-13 18:41:24 +00002164 */
dannarkf24479d2018-06-21 11:55:44 -07002165 private static Object convertFromBuildLangType(
2166 Rule rule,
2167 Attribute attr,
2168 Object buildLangValue,
2169 ImmutableMap<RepositoryName, RepositoryName> repositoryMapping)
Mark Schalleree624452016-01-13 18:41:24 +00002170 throws ConversionException {
dannarkf24479d2018-06-21 11:55:44 -07002171 LabelConversionContext context = new LabelConversionContext(rule.getLabel(), repositoryMapping);
2172 Object converted =
2173 BuildType.selectableConvert(
2174 attr.getType(),
2175 buildLangValue,
2176 new AttributeConversionContext(attr.getName(), rule.getRuleClass()),
2177 context);
Mark Schalleree624452016-01-13 18:41:24 +00002178
2179 if ((converted instanceof SelectorList<?>) && !attr.isConfigurable()) {
2180 throw new ConversionException(
2181 String.format("attribute \"%s\" is not configurable", attr.getName()));
2182 }
2183
laurentlb1d273cd2018-05-16 12:12:26 -07002184 if (converted instanceof List<?>) {
Mark Schalleree624452016-01-13 18:41:24 +00002185 if (attr.isOrderIndependent()) {
2186 @SuppressWarnings("unchecked")
2187 List<? extends Comparable<?>> list = (List<? extends Comparable<?>>) converted;
2188 converted = Ordering.natural().sortedCopy(list);
2189 }
2190 converted = ImmutableList.copyOf((List<?>) converted);
2191 }
2192
2193 return converted;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002194 }
2195
Michael Staibff938b32015-08-27 19:22:59 +00002196 /**
Michajlo Matijkiw7b7fce12016-09-20 19:52:07 +00002197 * Provides a {@link #toString()} description of the attribute being converted for
2198 * {@link BuildType#selectableConvert}. This is preferred over a raw string to avoid uselessly
2199 * constructing strings which are never used. A separate class instead of inline to avoid
2200 * accidental memory leaks.
2201 */
2202 private static class AttributeConversionContext {
2203 private final String attrName;
2204 private final String ruleClass;
2205
2206 AttributeConversionContext(String attrName, String ruleClass) {
2207 this.attrName = attrName;
2208 this.ruleClass = ruleClass;
2209 }
2210
2211 @Override
2212 public String toString() {
2213 return "attribute '" + attrName + "' in '" + ruleClass + "' rule";
2214 }
2215 }
2216
2217
2218 /**
Michael Staibff938b32015-08-27 19:22:59 +00002219 * Verifies that the rule has a valid value for the attribute according to its allowed values.
2220 *
2221 * <p>If the value for the given attribute on the given rule is invalid, an error will be recorded
2222 * in the given EventHandler.
2223 *
2224 * <p>If the rule is configurable, all of its potential values are evaluated, and errors for each
2225 * of the invalid values are reported.
2226 */
Mark Schalleree624452016-01-13 18:41:24 +00002227 private static void checkAllowedValues(
2228 Rule rule, Attribute attribute, EventHandler eventHandler) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002229 if (attribute.checkAllowedValues()) {
2230 PredicateWithMessage<Object> allowedValues = attribute.getAllowedValues();
Michael Staibff938b32015-08-27 19:22:59 +00002231 Iterable<?> values =
2232 AggregatingAttributeMapper.of(rule).visitAttribute(
2233 attribute.getName(), attribute.getType());
2234 for (Object value : values) {
2235 if (!allowedValues.apply(value)) {
Mark Schalleree624452016-01-13 18:41:24 +00002236 rule.reportError(
2237 String.format(
2238 "%s: invalid value in '%s' attribute: %s",
2239 rule.getLabel(),
2240 attribute.getName(),
2241 allowedValues.getErrorReason(value)),
2242 eventHandler);
Michael Staibff938b32015-08-27 19:22:59 +00002243 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002244 }
2245 }
2246 }
2247
Googler74558fc2016-05-06 21:47:42 +00002248 private static void checkAspectAllowedValues(
2249 Rule rule, EventHandler eventHandler) {
2250 for (Attribute attrOfRule : rule.getAttributes()) {
2251 for (Aspect aspect : attrOfRule.getAspects(rule)) {
2252 for (Attribute attrOfAspect : aspect.getDefinition().getAttributes().values()) {
2253 // By this point the AspectDefinition has been created and values assigned.
2254 if (attrOfAspect.checkAllowedValues()) {
2255 PredicateWithMessage<Object> allowedValues = attrOfAspect.getAllowedValues();
2256 Object value = attrOfAspect.getDefaultValue(rule);
2257 if (!allowedValues.apply(value)) {
2258 rule.reportError(
2259 String.format(
2260 "%s: invalid value in '%s' attribute: %s",
2261 rule.getLabel(),
2262 attrOfAspect.getName(),
2263 allowedValues.getErrorReason(value)),
2264 eventHandler);
2265 }
2266 }
2267 }
2268 }
2269 }
2270 }
2271
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002272 @Override
2273 public String toString() {
2274 return name;
2275 }
2276
2277 public boolean isDocumented() {
2278 return documented;
2279 }
2280
2281 public boolean isPublicByDefault() {
2282 return publicByDefault;
2283 }
2284
2285 /**
2286 * Returns true iff the outputs of this rule should be created beneath the
2287 * <i>bin</i> directory, false if beneath <i>genfiles</i>. For most rule
2288 * classes, this is a constant, but for genrule, it is a property of the
2289 * individual rule instance, derived from the 'output_to_bindir' attribute;
2290 * see Rule.hasBinaryOutput().
2291 */
Laurent Le Brunc2efe452015-04-08 16:27:21 +00002292 @VisibleForTesting
2293 public boolean hasBinaryOutput() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002294 return binaryOutput;
2295 }
2296
2297 /**
2298 * Returns this RuleClass's custom Skylark rule implementation.
2299 */
Francois-Rene Rideau95b0d0c2015-04-22 16:52:13 +00002300 @Nullable public BaseFunction getConfiguredTargetFunction() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002301 return configuredTargetFunction;
2302 }
2303
2304 /**
Lukacs Berki0e1a9942015-06-18 08:53:18 +00002305 * Returns a function that computes the external bindings a repository function contributes to
2306 * the WORKSPACE file.
2307 */
2308 public Function<? super Rule, Map<String, Label>> getExternalBindingsFunction() {
2309 return externalBindingsFunction;
2310 }
2311
2312 /**
mstaibe5538ad2017-04-04 18:32:23 +00002313 * Returns a function that computes the options referenced by a rule.
2314 */
2315 public Function<? super Rule, ? extends Set<String>> getOptionReferenceFunction() {
2316 return optionReferenceFunction;
2317 }
2318
2319 /**
janakrd3fe5e72018-03-30 12:49:12 -07002320 * For Skylark rule classes, returns this RuleClass's rule definition environment's label, which
2321 * is never null. Is null for native rules' RuleClass objects.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002322 */
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00002323 @Nullable
janakrd3fe5e72018-03-30 12:49:12 -07002324 public Label getRuleDefinitionEnvironmentLabel() {
2325 return ruleDefinitionEnvironmentLabel;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002326 }
2327
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00002328 /**
janakrd3fe5e72018-03-30 12:49:12 -07002329 * Returns the hash code for the RuleClass's rule definition environment. Will be null for native
2330 * rules' RuleClass objects.
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00002331 */
2332 @Nullable
2333 public String getRuleDefinitionEnvironmentHashCode() {
2334 return ruleDefinitionEnvironmentHashCode;
2335 }
2336
Jon Brandveinead58ae2016-09-29 18:41:10 +00002337 /** Returns true if this RuleClass is a Skylark-defined RuleClass. */
Michajlo Matijkiwbc042c62015-10-29 13:22:52 +00002338 public boolean isSkylark() {
2339 return isSkylark;
2340 }
2341
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002342 /**
Jon Brandveinead58ae2016-09-29 18:41:10 +00002343 * Returns true if this RuleClass is Skylark-defined and is subject to analysis-time
2344 * tests.
2345 */
2346 public boolean isSkylarkTestable() {
2347 return skylarkTestable;
2348 }
2349
2350 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002351 * Returns true if this rule class outputs a default executable for every rule.
2352 */
dslomov2ce98442017-10-23 19:14:02 +02002353 public boolean isExecutableSkylark() {
2354 return isExecutableSkylark;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002355 }
Brian Silvermand7d6d622016-03-17 09:53:39 +00002356
cparsons55781c92018-10-17 12:03:08 -07002357 /** Returns true if this rule class is an analysis test (set by analysis_test = true). */
2358 public boolean isAnalysisTest() {
2359 return isAnalysisTest;
2360 }
2361
Googlerc2200fd2018-09-14 17:35:59 -07002362 /**
2363 * Returns true if this rule class has the _whitelist_function_transition attribute.
2364 */
2365 public boolean hasFunctionTransitionWhitelist() {
2366 return hasFunctionTransitionWhitelist;
2367 }
2368
cpeyserfb829992017-09-07 17:17:03 +02002369 public ImmutableSet<Label> getRequiredToolchains() {
John Catereca28402017-05-17 21:44:12 +02002370 return requiredToolchains;
2371 }
2372
John Cater856b4dd2017-11-21 08:06:16 -08002373 public boolean supportsPlatforms() {
2374 return supportsPlatforms;
2375 }
2376
John Cateree45c662018-06-05 11:09:01 -07002377 public ExecutionPlatformConstraintsAllowed executionPlatformConstraintsAllowed() {
2378 return executionPlatformConstraintsAllowed;
2379 }
2380
2381 public ImmutableSet<Label> getExecutionPlatformConstraints() {
2382 return executionPlatformConstraints;
2383 }
2384
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07002385 @Nullable
2386 public OutputFile.Kind getOutputFileKind() {
2387 return outputFileKind;
2388 }
2389
Brian Silvermand7d6d622016-03-17 09:53:39 +00002390 public static boolean isThirdPartyPackage(PackageIdentifier packageIdentifier) {
2391 if (!packageIdentifier.getRepository().isMain()) {
2392 return false;
2393 }
2394
2395 if (!packageIdentifier.getPackageFragment().startsWith(THIRD_PARTY_PREFIX)) {
2396 return false;
2397 }
2398
2399 if (packageIdentifier.getPackageFragment().segmentCount() <= 1) {
2400 return false;
2401 }
2402
2403 return true;
2404 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002405}