Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Bazel Authors. All rights reserved. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 2 | // |
| 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 | |
| 15 | package com.google.devtools.build.lib.packages; |
| 16 | |
janakr | dc8b2e9a | 2017-08-18 22:52:37 +0200 | [diff] [blame] | 17 | import static com.google.devtools.build.lib.packages.BuildType.TRISTATE; |
Googler | c5fcc86 | 2019-09-06 16:17:47 -0700 | [diff] [blame] | 18 | import static com.google.devtools.build.lib.packages.Type.BOOLEAN; |
janakr | dc8b2e9a | 2017-08-18 22:52:37 +0200 | [diff] [blame] | 19 | |
tomlu | a155b53 | 2017-11-08 20:12:47 +0100 | [diff] [blame] | 20 | import com.google.common.base.Preconditions; |
Lukacs Berki | 9f74dfb | 2016-11-11 10:00:53 +0000 | [diff] [blame] | 21 | import com.google.common.base.Predicate; |
Klaus Aehlig | 6afb4fd | 2019-03-04 12:17:19 -0800 | [diff] [blame] | 22 | import com.google.common.base.Strings; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 23 | import com.google.common.collect.ImmutableMap; |
ulfjack | 5b79098 | 2018-04-25 07:09:13 -0700 | [diff] [blame] | 24 | import com.google.common.collect.Maps; |
Googler | edb893d | 2020-06-18 11:16:15 -0700 | [diff] [blame^] | 25 | import com.google.devtools.build.lib.actions.ExecutionRequirements; |
Lukacs Berki | 6e91eb9 | 2015-09-21 09:12:37 +0000 | [diff] [blame] | 26 | import com.google.devtools.build.lib.cmdline.Label; |
Googler | a9c9363 | 2019-11-13 10:48:07 -0800 | [diff] [blame] | 27 | import com.google.devtools.build.lib.syntax.Dict; |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 28 | import com.google.devtools.build.lib.syntax.EvalException; |
adonovan | f5262c5 | 2020-04-02 09:25:14 -0700 | [diff] [blame] | 29 | import com.google.devtools.build.lib.syntax.Location; |
Lukacs Berki | 9f74dfb | 2016-11-11 10:00:53 +0000 | [diff] [blame] | 30 | import com.google.devtools.build.lib.util.Pair; |
janakr | dc8b2e9a | 2017-08-18 22:52:37 +0200 | [diff] [blame] | 31 | import java.util.ArrayList; |
Lukacs Berki | 9f74dfb | 2016-11-11 10:00:53 +0000 | [diff] [blame] | 32 | import java.util.Collection; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 33 | import java.util.HashMap; |
Lukacs Berki | 9f74dfb | 2016-11-11 10:00:53 +0000 | [diff] [blame] | 34 | import java.util.List; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 35 | import java.util.Map; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 36 | import javax.annotation.Nullable; |
| 37 | |
| 38 | /** |
| 39 | * Utility functions over Targets that don't really belong in the base {@link |
| 40 | * Target} interface. |
| 41 | */ |
| 42 | public final class TargetUtils { |
| 43 | |
| 44 | // *_test / test_suite attribute that used to specify constraint keywords. |
| 45 | private static final String CONSTRAINTS_ATTR = "tags"; |
| 46 | |
ulfjack | 5b79098 | 2018-04-25 07:09:13 -0700 | [diff] [blame] | 47 | // We don't want to pollute the execution info with random things, and we also need to reserve |
| 48 | // some internal tags that we don't allow to be set on targets. We also don't want to |
| 49 | // exhaustively enumerate all the legal values here. Right now, only a ~small set of tags is |
| 50 | // recognized by Bazel. |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 51 | private static boolean legalExecInfoKeys(String tag) { |
| 52 | return tag.startsWith("block-") |
| 53 | || tag.startsWith("requires-") |
| 54 | || tag.startsWith("no-") |
| 55 | || tag.startsWith("supports-") |
| 56 | || tag.startsWith("disable-") |
Googler | edb893d | 2020-06-18 11:16:15 -0700 | [diff] [blame^] | 57 | || tag.startsWith("cpu:") |
| 58 | || tag.equals(ExecutionRequirements.LOCAL) |
| 59 | || tag.equals(ExecutionRequirements.WORKER_KEY_MNEMONIC); |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 60 | } |
ulfjack | 5b79098 | 2018-04-25 07:09:13 -0700 | [diff] [blame] | 61 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 62 | private TargetUtils() {} // Uninstantiable. |
| 63 | |
| 64 | public static boolean isTestRuleName(String name) { |
| 65 | return name.endsWith("_test"); |
| 66 | } |
| 67 | |
| 68 | public static boolean isTestSuiteRuleName(String name) { |
| 69 | return name.equals("test_suite"); |
| 70 | } |
| 71 | |
| 72 | /** |
| 73 | * Returns true iff {@code target} is a {@code *_test} rule; excludes {@code |
| 74 | * test_suite}. |
| 75 | */ |
| 76 | public static boolean isTestRule(Target target) { |
| 77 | return (target instanceof Rule) && isTestRuleName(((Rule) target).getRuleClass()); |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * Returns true iff {@code target} is a {@code test_suite} rule. |
| 82 | */ |
| 83 | public static boolean isTestSuiteRule(Target target) { |
lberki | 231d77d | 2019-01-03 11:18:11 -0800 | [diff] [blame] | 84 | return target instanceof Rule && isTestSuiteRuleName(((Rule) target).getRuleClass()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 85 | } |
| 86 | |
lberki | 0073153 | 2019-11-18 04:42:35 -0800 | [diff] [blame] | 87 | /** Returns true iff {@code target} is an {@code alias} rule. */ |
| 88 | public static boolean isAlias(Target target) { |
| 89 | if (!(target instanceof Rule)) { |
| 90 | return false; |
| 91 | } |
| 92 | |
| 93 | Rule rule = (Rule) target; |
gregce | 74d84d4 | 2020-04-17 10:02:03 -0700 | [diff] [blame] | 94 | return !rule.getRuleClassObject().isStarlark() && rule.getRuleClass().equals("alias"); |
lberki | 0073153 | 2019-11-18 04:42:35 -0800 | [diff] [blame] | 95 | } |
| 96 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 97 | /** |
| 98 | * Returns true iff {@code target} is a {@code *_test} or {@code test_suite}. |
| 99 | */ |
| 100 | public static boolean isTestOrTestSuiteRule(Target target) { |
| 101 | return isTestRule (target) || isTestSuiteRule(target); |
| 102 | } |
| 103 | |
| 104 | /** |
| 105 | * Returns true if {@code target} has "manual" in the tags attribute and thus should be ignored by |
| 106 | * command-line wildcards or by test_suite $implicit_tests attribute. |
| 107 | */ |
| 108 | public static boolean hasManualTag(Target target) { |
| 109 | return (target instanceof Rule) && hasConstraint((Rule) target, "manual"); |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * Returns true if test marked as "exclusive" by the appropriate keyword |
| 114 | * in the tags attribute. |
| 115 | * |
| 116 | * Method assumes that passed target is a test rule, so usually it should be |
| 117 | * used only after isTestRule() or isTestOrTestSuiteRule(). Behavior is |
| 118 | * undefined otherwise. |
| 119 | */ |
| 120 | public static boolean isExclusiveTestRule(Rule rule) { |
| 121 | return hasConstraint(rule, "exclusive"); |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Returns true if test marked as "local" by the appropriate keyword |
| 126 | * in the tags attribute. |
| 127 | * |
| 128 | * Method assumes that passed target is a test rule, so usually it should be |
| 129 | * used only after isTestRule() or isTestOrTestSuiteRule(). Behavior is |
| 130 | * undefined otherwise. |
| 131 | */ |
| 132 | public static boolean isLocalTestRule(Rule rule) { |
| 133 | return hasConstraint(rule, "local") |
| 134 | || NonconfigurableAttributeMapper.of(rule).get("local", Type.BOOLEAN); |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * Returns true if the rule is a test or test suite and is local or exclusive. |
| 139 | * Wraps the above calls into one generic check safely applicable to any rule. |
| 140 | */ |
| 141 | public static boolean isTestRuleAndRunsLocally(Rule rule) { |
lberki | 231d77d | 2019-01-03 11:18:11 -0800 | [diff] [blame] | 142 | return isTestOrTestSuiteRule(rule) && (isLocalTestRule(rule) || isExclusiveTestRule(rule)); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | /** |
| 146 | * Returns true if test marked as "external" by the appropriate keyword |
| 147 | * in the tags attribute. |
| 148 | * |
| 149 | * Method assumes that passed target is a test rule, so usually it should be |
| 150 | * used only after isTestRule() or isTestOrTestSuiteRule(). Behavior is |
| 151 | * undefined otherwise. |
| 152 | */ |
| 153 | public static boolean isExternalTestRule(Rule rule) { |
| 154 | return hasConstraint(rule, "external"); |
| 155 | } |
| 156 | |
janakr | dc8b2e9a | 2017-08-18 22:52:37 +0200 | [diff] [blame] | 157 | public static List<String> getStringListAttr(Target target, String attrName) { |
| 158 | Preconditions.checkArgument(target instanceof Rule); |
| 159 | return NonconfigurableAttributeMapper.of((Rule) target).get(attrName, Type.STRING_LIST); |
| 160 | } |
| 161 | |
| 162 | public static String getStringAttr(Target target, String attrName) { |
| 163 | Preconditions.checkArgument(target instanceof Rule); |
| 164 | return NonconfigurableAttributeMapper.of((Rule) target).get(attrName, Type.STRING); |
| 165 | } |
| 166 | |
| 167 | public static Iterable<String> getAttrAsString(Target target, String attrName) { |
| 168 | Preconditions.checkArgument(target instanceof Rule); |
| 169 | List<String> values = new ArrayList<>(); // May hold null values. |
| 170 | Attribute attribute = ((Rule) target).getAttributeDefinition(attrName); |
| 171 | if (attribute != null) { |
| 172 | Type<?> attributeType = attribute.getType(); |
| 173 | for (Object attrValue : |
| 174 | AggregatingAttributeMapper.of((Rule) target) |
| 175 | .visitAttribute(attribute.getName(), attributeType)) { |
| 176 | |
| 177 | // Ugly hack to maintain backward 'attr' query compatibility for BOOLEAN and TRISTATE |
| 178 | // attributes. These are internally stored as actual Boolean or TriState objects but were |
| 179 | // historically queried as integers. To maintain compatibility, we inspect their actual |
| 180 | // value and return the integer equivalent represented as a String. This code is the |
| 181 | // opposite of the code in BooleanType and TriStateType respectively. |
| 182 | if (attributeType == BOOLEAN) { |
| 183 | values.add(Type.BOOLEAN.cast(attrValue) ? "1" : "0"); |
| 184 | } else if (attributeType == TRISTATE) { |
| 185 | switch (BuildType.TRISTATE.cast(attrValue)) { |
| 186 | case AUTO: |
| 187 | values.add("-1"); |
| 188 | break; |
| 189 | case NO: |
| 190 | values.add("0"); |
| 191 | break; |
| 192 | case YES: |
| 193 | values.add("1"); |
| 194 | break; |
| 195 | default: |
| 196 | throw new AssertionError("This can't happen!"); |
| 197 | } |
| 198 | } else { |
| 199 | values.add(attrValue == null ? null : attrValue.toString()); |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | return values; |
| 204 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 205 | |
| 206 | /** |
| 207 | * If the given target is a rule, returns its <code>deprecation<code/> value, or null if unset. |
| 208 | */ |
| 209 | @Nullable |
| 210 | public static String getDeprecation(Target target) { |
| 211 | if (!(target instanceof Rule)) { |
| 212 | return null; |
| 213 | } |
| 214 | Rule rule = (Rule) target; |
| 215 | return (rule.isAttrDefined("deprecation", Type.STRING)) |
| 216 | ? NonconfigurableAttributeMapper.of(rule).get("deprecation", Type.STRING) |
| 217 | : null; |
| 218 | } |
| 219 | |
| 220 | /** |
| 221 | * Checks whether specified constraint keyword is present in the |
| 222 | * tags attribute of the test or test suite rule. |
| 223 | * |
| 224 | * Method assumes that provided rule is a test or a test suite. Behavior is |
| 225 | * undefined otherwise. |
| 226 | */ |
| 227 | private static boolean hasConstraint(Rule rule, String keyword) { |
| 228 | return NonconfigurableAttributeMapper.of(rule).get(CONSTRAINTS_ATTR, Type.STRING_LIST) |
| 229 | .contains(keyword); |
| 230 | } |
| 231 | |
| 232 | /** |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 233 | * Returns the execution info from the tags declared on the target. These include only some tags |
| 234 | * {@link #legalExecInfoKeys} as keys with empty values. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 235 | */ |
| 236 | public static Map<String, String> getExecutionInfo(Rule rule) { |
| 237 | // tags may contain duplicate values. |
| 238 | Map<String, String> map = new HashMap<>(); |
| 239 | for (String tag : |
| 240 | NonconfigurableAttributeMapper.of(rule).get(CONSTRAINTS_ATTR, Type.STRING_LIST)) { |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 241 | if (legalExecInfoKeys(tag)) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 242 | map.put(tag, ""); |
| 243 | } |
| 244 | } |
| 245 | return ImmutableMap.copyOf(map); |
| 246 | } |
| 247 | |
| 248 | /** |
ishikhman | 94c24b3 | 2019-08-30 04:46:25 -0700 | [diff] [blame] | 249 | * Returns the execution info from the tags declared on the target. These include only some tags |
| 250 | * {@link #legalExecInfoKeys} as keys with empty values. |
| 251 | * |
| 252 | * @param rule a rule instance to get tags from |
| 253 | * @param allowTagsPropagation if set to true, tags will be propagated from a target to the |
| 254 | * actions' execution requirements, for more details {@see |
gregce | 61ec8d1 | 2020-05-18 11:02:05 -0700 | [diff] [blame] | 255 | * StarlarkSemanticsOptions#experimentalAllowTagsPropagation} |
ishikhman | 94c24b3 | 2019-08-30 04:46:25 -0700 | [diff] [blame] | 256 | */ |
| 257 | public static ImmutableMap<String, String> getExecutionInfo( |
| 258 | Rule rule, boolean allowTagsPropagation) { |
| 259 | if (allowTagsPropagation) { |
| 260 | return ImmutableMap.copyOf(getExecutionInfo(rule)); |
| 261 | } else { |
| 262 | return ImmutableMap.of(); |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | /** |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 267 | * Returns the execution info, obtained from the rule's tags and the execution requirements |
| 268 | * provided. Only supported tags are included into the execution info, see {@link |
| 269 | * #legalExecInfoKeys}. |
| 270 | * |
| 271 | * @param executionRequirementsUnchecked execution_requirements of a rule, expected to be of a |
Googler | a9c9363 | 2019-11-13 10:48:07 -0800 | [diff] [blame] | 272 | * {@code Dict<String, String>} type, null or {@link |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 273 | * com.google.devtools.build.lib.syntax.Runtime#NONE} |
| 274 | * @param rule a rule instance to get tags from |
ishikhman | 7e83721 | 2019-08-21 03:22:35 -0700 | [diff] [blame] | 275 | * @param allowTagsPropagation if set to true, tags will be propagated from a target to the |
| 276 | * actions' execution requirements, for more details {@see |
gregce | 773b95f | 2020-05-19 09:51:09 -0700 | [diff] [blame] | 277 | * StarlarkSematicOptions#experimentalAllowTagsPropagation} |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 278 | */ |
| 279 | public static ImmutableMap<String, String> getFilteredExecutionInfo( |
adonovan | 8580390 | 2020-04-16 14:46:57 -0700 | [diff] [blame] | 280 | @Nullable Object executionRequirementsUnchecked, Rule rule, boolean allowTagsPropagation) |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 281 | throws EvalException { |
| 282 | Map<String, String> checkedExecutionRequirements = |
| 283 | TargetUtils.filter( |
adonovan | 8580390 | 2020-04-16 14:46:57 -0700 | [diff] [blame] | 284 | executionRequirementsUnchecked == null |
| 285 | ? ImmutableMap.of() |
| 286 | : Dict.noneableCast( |
| 287 | executionRequirementsUnchecked, |
| 288 | String.class, |
| 289 | String.class, |
| 290 | "execution_requirements")); |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 291 | |
| 292 | Map<String, String> executionInfoBuilder = new HashMap<>(); |
| 293 | // adding filtered execution requirements to the execution info map |
| 294 | executionInfoBuilder.putAll(checkedExecutionRequirements); |
| 295 | |
ishikhman | 7e83721 | 2019-08-21 03:22:35 -0700 | [diff] [blame] | 296 | if (allowTagsPropagation) { |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 297 | Map<String, String> checkedTags = getExecutionInfo(rule); |
| 298 | // merging filtered tags to the execution info map avoiding duplicates |
| 299 | checkedTags.forEach(executionInfoBuilder::putIfAbsent); |
| 300 | } |
| 301 | |
| 302 | return ImmutableMap.copyOf(executionInfoBuilder); |
| 303 | } |
| 304 | |
| 305 | /** |
ulfjack | 5b79098 | 2018-04-25 07:09:13 -0700 | [diff] [blame] | 306 | * Returns the execution info. These include execution requirement tags ('block-*', 'requires-*', |
| 307 | * 'no-*', 'supports-*', 'disable-*', 'local', and 'cpu:*') as keys with empty values. |
| 308 | */ |
| 309 | public static Map<String, String> filter(Map<String, String> executionInfo) { |
ishikhman | 53ee8c3 | 2019-07-17 01:18:14 -0700 | [diff] [blame] | 310 | return Maps.filterKeys(executionInfo, TargetUtils::legalExecInfoKeys); |
ulfjack | 5b79098 | 2018-04-25 07:09:13 -0700 | [diff] [blame] | 311 | } |
| 312 | |
| 313 | /** |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 314 | * Returns the language part of the rule name (e.g. "foo" for foo_test or foo_binary). |
| 315 | * |
| 316 | * <p>In practice this is the part before the "_", if any, otherwise the entire rule class name. |
| 317 | * |
| 318 | * <p>Precondition: isTestRule(target) || isRunnableNonTestRule(target). |
| 319 | */ |
| 320 | public static String getRuleLanguage(Target target) { |
| 321 | return getRuleLanguage(((Rule) target).getRuleClass()); |
| 322 | } |
| 323 | |
| 324 | /** |
| 325 | * Returns the language part of the rule name (e.g. "foo" for foo_test or foo_binary). |
| 326 | * |
| 327 | * <p>In practice this is the part before the "_", if any, otherwise the entire rule class name. |
| 328 | */ |
| 329 | public static String getRuleLanguage(String ruleClass) { |
Ulf Adams | 07dba94 | 2015-03-05 14:47:37 +0000 | [diff] [blame] | 330 | int index = ruleClass.lastIndexOf('_'); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 331 | // Chop off "_binary" or "_test". |
| 332 | return index != -1 ? ruleClass.substring(0, index) : ruleClass; |
| 333 | } |
| 334 | |
lberki | 231d77d | 2019-01-03 11:18:11 -0800 | [diff] [blame] | 335 | private static boolean isExplicitDependency(Rule rule, Label label) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 336 | if (rule.getVisibility().getDependencyLabels().contains(label)) { |
| 337 | return true; |
| 338 | } |
| 339 | |
janakr | d0a3c5e | 2018-08-09 15:59:24 -0700 | [diff] [blame] | 340 | for (AttributeMap.DepEdge depEdge : AggregatingAttributeMapper.of(rule).visitLabels()) { |
| 341 | if (rule.isAttributeValueExplicitlySpecified(depEdge.getAttribute()) |
| 342 | && label.equals(depEdge.getLabel())) { |
| 343 | return true; |
| 344 | } |
| 345 | } |
| 346 | return false; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 347 | } |
| 348 | |
Lukacs Berki | 9f74dfb | 2016-11-11 10:00:53 +0000 | [diff] [blame] | 349 | /** |
| 350 | * Returns a predicate to be used for test tag filtering, i.e., that only accepts tests that match |
| 351 | * all of the required tags and none of the excluded tags. |
| 352 | */ |
| 353 | public static Predicate<Target> tagFilter(List<String> tagFilterList) { |
| 354 | Pair<Collection<String>, Collection<String>> tagLists = |
| 355 | TestTargetUtils.sortTagsBySense(tagFilterList); |
| 356 | final Collection<String> requiredTags = tagLists.first; |
| 357 | final Collection<String> excludedTags = tagLists.second; |
laurentlb | 3d2a68c | 2017-06-30 00:32:04 +0200 | [diff] [blame] | 358 | return input -> { |
| 359 | if (requiredTags.isEmpty() && excludedTags.isEmpty()) { |
| 360 | return true; |
Lukacs Berki | 9f74dfb | 2016-11-11 10:00:53 +0000 | [diff] [blame] | 361 | } |
laurentlb | 3d2a68c | 2017-06-30 00:32:04 +0200 | [diff] [blame] | 362 | |
| 363 | if (!(input instanceof Rule)) { |
lberki | 1fa2dfb | 2017-12-05 07:11:03 -0800 | [diff] [blame] | 364 | return requiredTags.isEmpty(); |
laurentlb | 3d2a68c | 2017-06-30 00:32:04 +0200 | [diff] [blame] | 365 | } |
ulfjack | aa2ff99 | 2018-06-07 07:05:37 -0700 | [diff] [blame] | 366 | // Note that test_tags are those originating from the XX_test rule, whereas the requiredTags |
| 367 | // and excludedTags originate from the command line or test_suite rule. |
| 368 | // TODO(ulfjack): getRuleTags is inconsistent with TestFunction and other places that use |
| 369 | // tags + size, but consistent with TestSuite. |
laurentlb | 3d2a68c | 2017-06-30 00:32:04 +0200 | [diff] [blame] | 370 | return TestTargetUtils.testMatchesFilters( |
| 371 | ((Rule) input).getRuleTags(), requiredTags, excludedTags, false); |
Lukacs Berki | 9f74dfb | 2016-11-11 10:00:53 +0000 | [diff] [blame] | 372 | }; |
| 373 | } |
| 374 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 375 | /** |
| 376 | * Return {@link Location} for {@link Target} target, if it should not be null. |
| 377 | */ |
| 378 | public static Location getLocationMaybe(Target target) { |
| 379 | return (target instanceof Rule) || (target instanceof InputFile) ? target.getLocation() : null; |
| 380 | } |
| 381 | |
| 382 | /** |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 383 | * Return nicely formatted error message that {@link Label} label that was pointed to by {@link |
| 384 | * Target} target did not exist, due to {@link NoSuchThingException} e. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 385 | */ |
Janak Ramakrishnan | 3c0adb2 | 2016-08-15 21:54:55 +0000 | [diff] [blame] | 386 | public static String formatMissingEdge( |
Klaus Aehlig | 6afb4fd | 2019-03-04 12:17:19 -0800 | [diff] [blame] | 387 | @Nullable Target target, Label label, NoSuchThingException e, @Nullable Attribute attr) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 388 | // instanceof returns false if target is null (which is exploited here) |
| 389 | if (target instanceof Rule) { |
| 390 | Rule rule = (Rule) target; |
Nathan Harmata | c1563c2 | 2016-01-29 23:03:03 +0000 | [diff] [blame] | 391 | if (isExplicitDependency(rule, label)) { |
| 392 | return String.format("%s and referenced by '%s'", e.getMessage(), target.getLabel()); |
| 393 | } else { |
Klaus Aehlig | 6afb4fd | 2019-03-04 12:17:19 -0800 | [diff] [blame] | 394 | String additionalInfo = ""; |
| 395 | if (attr != null && !Strings.isNullOrEmpty(attr.getDoc())) { |
| 396 | additionalInfo = |
| 397 | String.format( |
| 398 | "\nDocumentation for implicit attribute %s of rules of type %s:\n%s", |
| 399 | attr.getPublicName(), rule.getRuleClass(), attr.getDoc()); |
| 400 | } |
Nathan Harmata | c1563c2 | 2016-01-29 23:03:03 +0000 | [diff] [blame] | 401 | // N.B. If you see this error message in one of our integration tests during development of |
| 402 | // a change that adds a new implicit dependency when running Blaze, maybe you forgot to add |
| 403 | // a new mock target to the integration test's setup. |
Klaus Aehlig | 6afb4fd | 2019-03-04 12:17:19 -0800 | [diff] [blame] | 404 | return String.format( |
| 405 | "every rule of type %s implicitly depends upon the target '%s', but " |
| 406 | + "this target could not be found because of: %s%s", |
| 407 | rule.getRuleClass(), label, e.getMessage(), additionalInfo); |
Nathan Harmata | c1563c2 | 2016-01-29 23:03:03 +0000 | [diff] [blame] | 408 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 409 | } else if (target instanceof InputFile) { |
| 410 | return e.getMessage() + " (this is usually caused by a missing package group in the" |
| 411 | + " package-level visibility declaration)"; |
| 412 | } else { |
| 413 | if (target != null) { |
Nathan Harmata | c1563c2 | 2016-01-29 23:03:03 +0000 | [diff] [blame] | 414 | return String.format("in target '%s', no such label '%s': %s", target.getLabel(), label, |
| 415 | e.getMessage()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 416 | } |
| 417 | return e.getMessage(); |
| 418 | } |
| 419 | } |
Klaus Aehlig | 6afb4fd | 2019-03-04 12:17:19 -0800 | [diff] [blame] | 420 | |
| 421 | public static String formatMissingEdge( |
| 422 | @Nullable Target target, Label label, NoSuchThingException e) { |
| 423 | return formatMissingEdge(target, label, e, null); |
| 424 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 425 | } |