Skip to content

Commit dc65b92

Browse files
Introduce flags to allow filtering of targets by rule name
This commit introduces two new flags: `--build_rule_filters` & `--test_rule_filters`. They behave in a very similar manner to existing filter flags, e.g. tag, timeout, size, lang, etc., and will allow users to filter out or in targets for building/testing that use a specific rule.
1 parent f1ae4b8 commit dc65b92

File tree

7 files changed

+117
-7
lines changed

7 files changed

+117
-7
lines changed

src/main/java/com/google/devtools/build/lib/packages/TargetUtils.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,29 @@ public static Predicate<Target> tagFilter(List<String> tagFilterList) {
381381
};
382382
}
383383

384+
/**
385+
* Returns a predicate to be used for test rule name filtering, i.e., that only accepts tests that match
386+
* a required rule name and not an excluded rule name.
387+
*/
388+
public static Predicate<Target> ruleFilter(List<String> ruleFilterList) {
389+
Pair<Collection<String>, Collection<String>> ruleLists =
390+
TestTargetUtils.sortTagsBySense(ruleFilterList);
391+
final Collection<String> requiredRules = ruleLists.first;
392+
final Collection<String> excludedRules = ruleLists.second;
393+
return input -> {
394+
if (requiredRules.isEmpty() && excludedRules.isEmpty()) {
395+
return true;
396+
}
397+
398+
if (!(input instanceof Rule)) {
399+
return requiredRules.isEmpty();
400+
}
401+
402+
return TestTargetUtils.testMatchesRuleFilters(
403+
((Rule) input).getRuleClass(), requiredRules, excludedRules);
404+
};
405+
}
406+
384407
/** Return {@link Location} for {@link Target} target, if it should not be null. */
385408
@Nullable
386409
public static Location getLocationMaybe(Target target) {

src/main/java/com/google/devtools/build/lib/packages/TestTargetUtils.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ private static boolean testMatchesFilters(
9191
return testMatchesFilters(testTags, requiredTags, excludedTags);
9292
}
9393

94+
/**
95+
* Returns whether a test with a rule name matches a filter (as specified by the set
96+
* of its positive and its negative filters).
97+
*/
98+
public static boolean testMatchesRuleFilters(
99+
String ruleName,
100+
Collection<String> requiredRules,
101+
Collection<String> excludedRules) {
102+
return (requiredRules.isEmpty() || requiredRules.contains(ruleName)) &&
103+
!excludedRules.contains(ruleName);
104+
}
105+
94106
/**
95107
* Filters 'tests' (by mutation) according to the 'tags' attribute, specifically those that
96108
* match ALL of the tags in tagsAttribute.

src/main/java/com/google/devtools/build/lib/pkgcache/LoadingOptions.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,35 @@ public class LoadingOptions extends OptionsBase {
128128
)
129129
public List<String> testLangFilterList;
130130

131+
@Option(
132+
name = "build_rule_filters",
133+
converter = CommaSeparatedOptionListConverter.class,
134+
defaultValue = "",
135+
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
136+
effectTags = {OptionEffectTag.UNKNOWN},
137+
help =
138+
"Specifies a comma-separated list of rule names. Each rule name can be optionally "
139+
+ "preceded with '-' to specify excluded rule names. Only those targets will be built that "
140+
+ "equal the positive rule name or do not equal the negative rule name. This option "
141+
+ "does not affect the set of tests executed with the 'test' command; those are be "
142+
+ "governed by the test filtering options, for example '--test_rule_filters'"
143+
)
144+
public List<String> buildRuleFilterList;
145+
146+
@Option(
147+
name = "test_rule_filters",
148+
converter = CommaSeparatedOptionListConverter.class,
149+
defaultValue = "",
150+
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
151+
effectTags = {OptionEffectTag.UNKNOWN},
152+
help =
153+
"Specifies a comma-separated list of rule names. Each rule name can be optionally "
154+
+ "preceded with '-' to specify excluded rule names. Only those test targets will be "
155+
+ "found that equal the positive rule name or do not equal the negative rule name."
156+
+ "This option affects --build_tests_only behavior and the test command."
157+
)
158+
public List<String> testRuleFilterList;
159+
131160
@Option(
132161
name = "build_manual_tests",
133162
defaultValue = "false",

src/main/java/com/google/devtools/build/lib/pkgcache/TestFilter.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,29 @@ public static TestFilter forOptions(LoadingOptions options) {
4646
ImmutableSet.copyOf(options.testSizeFilterSet),
4747
ImmutableSet.copyOf(options.testTimeoutFilterSet),
4848
ImmutableList.copyOf(options.testTagFilterList),
49-
ImmutableList.copyOf(options.testLangFilterList));
49+
ImmutableList.copyOf(options.testLangFilterList),
50+
ImmutableList.copyOf(options.testRuleFilterList));
5051
}
5152

5253
private final ImmutableSet<TestSize> testSizeFilterSet;
5354
private final ImmutableSet<TestTimeout> testTimeoutFilterSet;
5455
private final ImmutableList<String> testTagFilterList;
5556
private final ImmutableList<String> testLangFilterList;
57+
private final ImmutableList<String> testRuleFilterList;
5658
private final Predicate<Target> impl;
5759

5860
@VisibleForSerialization
5961
TestFilter(
6062
ImmutableSet<TestSize> testSizeFilterSet,
6163
ImmutableSet<TestTimeout> testTimeoutFilterSet,
6264
ImmutableList<String> testTagFilterList,
63-
ImmutableList<String> testLangFilterList) {
65+
ImmutableList<String> testLangFilterList,
66+
ImmutableList<String> testRuleFilterList) {
6467
this.testSizeFilterSet = testSizeFilterSet;
6568
this.testTimeoutFilterSet = testTimeoutFilterSet;
6669
this.testTagFilterList = testTagFilterList;
6770
this.testLangFilterList = testLangFilterList;
71+
this.testRuleFilterList = testRuleFilterList;
6872
Predicate<Target> testFilter = ALWAYS_TRUE;
6973
if (!testSizeFilterSet.isEmpty()) {
7074
testFilter = testFilter.and(testSizeFilter(testSizeFilterSet));
@@ -78,6 +82,9 @@ public static TestFilter forOptions(LoadingOptions options) {
7882
if (!testLangFilterList.isEmpty()) {
7983
testFilter = testFilter.and(testLangFilter(testLangFilterList));
8084
}
85+
if (!testRuleFilterList.isEmpty()) {
86+
testFilter = testFilter.and(testRuleFilter(testRuleFilterList));
87+
}
8188
impl = testFilter;
8289
}
8390

@@ -89,7 +96,7 @@ public boolean apply(@Nullable Target input) {
8996
@Override
9097
public int hashCode() {
9198
return Objects.hash(testSizeFilterSet, testTimeoutFilterSet, testTagFilterList,
92-
testLangFilterList);
99+
testLangFilterList, testRuleFilterList);
93100
}
94101

95102
@Override
@@ -103,7 +110,8 @@ public boolean equals(Object o) {
103110
return f.testSizeFilterSet.equals(testSizeFilterSet)
104111
&& f.testTimeoutFilterSet.equals(testTimeoutFilterSet)
105112
&& f.testTagFilterList.equals(testTagFilterList)
106-
&& f.testLangFilterList.equals(testLangFilterList);
113+
&& f.testLangFilterList.equals(testLangFilterList)
114+
&& f.testRuleFilterList.equals(testRuleFilterList);
107115
}
108116

109117
@Override
@@ -113,6 +121,7 @@ public String toString() {
113121
.add("testTimeoutFilterSet", testTimeoutFilterSet)
114122
.add("testTagFilterList", testTagFilterList)
115123
.add("testLangFilterList", testLangFilterList)
124+
.add("testRuleFilterList", testRuleFilterList)
116125
.toString();
117126
}
118127

@@ -159,4 +168,28 @@ private static Predicate<Target> testLangFilter(List<String> langFilterList) {
159168
&& !excludedLangs.contains(ruleLang);
160169
};
161170
}
171+
172+
/**
173+
* Returns a predicate to be used for test rule filtering, i.e., that only accepts tests of
174+
* the specified rule names.
175+
*/
176+
private static Predicate<Target> testRuleFilter(List<String> ruleFilterList) {
177+
final Set<String> requiredRules = new HashSet<>();
178+
final Set<String> excludedRules = new HashSet<>();
179+
180+
for (String ruleFilter : ruleFilterList) {
181+
if (ruleFilter.startsWith("-")) {
182+
ruleFilter = ruleFilter.substring(1);
183+
excludedRules.add(ruleFilter);
184+
} else {
185+
requiredRules.add(ruleFilter);
186+
}
187+
}
188+
189+
return rule -> {
190+
String ruleName = rule.getRuleClass();
191+
return (requiredRules.isEmpty() || requiredRules.contains(ruleName))
192+
&& !excludedRules.contains(ruleName);
193+
};
194+
}
162195
}

src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3002,6 +3002,7 @@ public TargetPatternPhaseValue loadTargetPatternsWithFilters(
30023002
options.buildTestsOnly,
30033003
determineTests,
30043004
ImmutableList.copyOf(options.buildTagFilterList),
3005+
ImmutableList.copyOf(options.buildRuleFilterList),
30053006
options.buildManualTests,
30063007
options.expandTestSuites,
30073008
TestFilter.forOptions(options));

src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,10 @@ private static ResolvedTargets<Target> mergeAll(
367367
}
368368
}
369369

370-
ResolvedTargets<Target> result =
371-
builder.filter(TargetUtils.tagFilter(options.getBuildTargetFilter())).build();
370+
builder.filter(TargetUtils.tagFilter(options.getBuildTargetFilter()));
371+
builder.filter(TargetUtils.ruleFilter(options.getBuildRuleFilter()));
372+
373+
ResolvedTargets<Target> result = builder.build();
372374
if (options.getCompileOneDependency()) {
373375
EnvironmentBackedRecursivePackageProvider environmentBackedRecursivePackageProvider =
374376
new EnvironmentBackedRecursivePackageProvider(env);

src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseValue.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ public static TargetPatternPhaseKey key(
155155
boolean buildTestsOnly,
156156
boolean determineTests,
157157
ImmutableList<String> buildTargetFilter,
158+
ImmutableList<String> buildRuleFilter,
158159
boolean buildManualTests,
159160
boolean expandTestSuites,
160161
@Nullable TestFilter testFilter) {
@@ -165,6 +166,7 @@ public static TargetPatternPhaseKey key(
165166
buildTestsOnly,
166167
determineTests,
167168
buildTargetFilter,
169+
buildRuleFilter,
168170
buildManualTests,
169171
expandTestSuites,
170172
testFilter);
@@ -181,7 +183,7 @@ public static TargetPatternPhaseKey key(
181183
public static SkyKey keyWithoutFilters(
182184
ImmutableList<String> targetPatterns, PathFragment offset) {
183185
return new TargetPatternPhaseKey(
184-
targetPatterns, offset, false, false, false, ImmutableList.of(), false, false, null);
186+
targetPatterns, offset, false, false, false, ImmutableList.of(), ImmutableList.of(), false, false, null);
185187
}
186188

187189
/** The configuration needed to run the target pattern evaluation phase. */
@@ -194,6 +196,7 @@ static final class TargetPatternPhaseKey implements SkyKey {
194196
private final boolean buildTestsOnly;
195197
private final boolean determineTests;
196198
private final ImmutableList<String> buildTargetFilter;
199+
private final ImmutableList<String> buildRuleFilter;
197200
private final boolean buildManualTests;
198201
private final boolean expandTestSuites;
199202
@Nullable private final TestFilter testFilter;
@@ -205,6 +208,7 @@ private TargetPatternPhaseKey(
205208
boolean buildTestsOnly,
206209
boolean determineTests,
207210
ImmutableList<String> buildTargetFilter,
211+
ImmutableList<String> buildRuleFilter,
208212
boolean buildManualTests,
209213
boolean expandTestSuites,
210214
@Nullable TestFilter testFilter) {
@@ -214,6 +218,7 @@ private TargetPatternPhaseKey(
214218
this.buildTestsOnly = buildTestsOnly;
215219
this.determineTests = determineTests;
216220
this.buildTargetFilter = Preconditions.checkNotNull(buildTargetFilter);
221+
this.buildRuleFilter = Preconditions.checkNotNull(buildRuleFilter);
217222
this.buildManualTests = buildManualTests;
218223
this.expandTestSuites = expandTestSuites;
219224
this.testFilter = testFilter;
@@ -251,6 +256,10 @@ public ImmutableList<String> getBuildTargetFilter() {
251256
return buildTargetFilter;
252257
}
253258

259+
public ImmutableList<String> getBuildRuleFilter() {
260+
return buildRuleFilter;
261+
}
262+
254263
public boolean getBuildManualTests() {
255264
return buildManualTests;
256265
}
@@ -305,6 +314,7 @@ public boolean equals(Object obj) {
305314
&& other.buildTestsOnly == buildTestsOnly
306315
&& other.determineTests == determineTests
307316
&& other.buildTargetFilter.equals(buildTargetFilter)
317+
&& other.buildRuleFilter.equals(buildRuleFilter)
308318
&& other.buildManualTests == buildManualTests
309319
&& other.expandTestSuites == expandTestSuites
310320
&& Objects.equals(other.testFilter, testFilter);

0 commit comments

Comments
 (0)