forked from pantsbuild/pants
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a global --tag option to filter targets based on their tags.
--tag=foo,bar includes only targets that have at least one of those tags. --tag=-foo,bar includes only targets that have none of those tags. --tag=foo,bar --tag=-baz includes only targets that have at least one of the tags foo or bar, and do not have the tag baz. The filtering is on target roots, of course, similar to spec_excludes and exclude_target_regexp. Dependencies are included in the targets passed to Task.execute() regardless of their tags. We already had similar filtering functionality in the Filter task. So I refactored some of that into a new filtering.py file under util. While doing so, I noticed that the help text on Filter's options was wrong: In --tag=-foo,bar the '-' prefix applies to both foo and bar, and --tag=-foo,+bar is not sensible. While fixing up the help strings I realized that it would be more succinct to move the common help text (the part explaining about the prefix and how multiple filters are specified) into the goal description. Then I realized that it would be pretty verbose to put that in the with_description() text in register.py, so I added a little thing that uses the task's docstring as the description, if one isn't provided explicitly. Note that Filter still has its own --tag option, which we can think about deprecating in a future change. IMPORTANT: While testing, I noticed that we had a longstanding bug, where multiple filters of the same type wouldn't work, because in the loop the filter() function was capturing the same references in its closure on each iteration. See the test I added in test_filter.py - that test fails with no other changes at HEAD. Also note that the test marked as xfail is behaving as intended: according to the implementation, separate specifications of the same option are ANDed (while comma-separated values in a single specification are ORed). If we want the behavior to be different then we can discuss, but for now at least that xfail was inappropriate and misleading. Testing Done: CI passes: https://travis-ci.org/pantsbuild/pants/builds/66695055 Reviewed at https://rbcommons.com/s/twitter/r/2362/
- Loading branch information
Showing
13 changed files
with
254 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# coding=utf-8 | ||
# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
from __future__ import (absolute_import, division, generators, nested_scopes, print_function, | ||
unicode_literals, with_statement) | ||
|
||
import copy | ||
import operator | ||
|
||
|
||
_identity = lambda x: x | ||
|
||
|
||
def _extract_modifier(modified_param): | ||
if modified_param.startswith('+'): | ||
return _identity, modified_param[1:] | ||
elif modified_param.startswith('-'): | ||
return operator.not_, modified_param[1:] | ||
else: | ||
return _identity, modified_param | ||
|
||
|
||
def create_filters(predicate_params, predicate_factory): | ||
"""Create filter functions from a list of string parameters. | ||
:param predicate_params: A list of predicate_param arguments as in `create_filter`. | ||
:param predicate_factory: As in `create_filter`. | ||
""" | ||
filters = [] | ||
for predicate_param in predicate_params: | ||
filters.append(create_filter(predicate_param, predicate_factory)) | ||
return filters | ||
|
||
|
||
def create_filter(predicate_param, predicate_factory): | ||
"""Create a filter function from a string parameter. | ||
:param predicate_param: Create a filter for this param string. Each string is a | ||
comma-separated list of arguments to the predicate_factory. | ||
If the entire comma-separated list is prefixed by a '-' then the | ||
sense of the resulting filter is inverted. | ||
:param predicate_factory: A function that takes a parameter and returns a predicate, i.e., a | ||
function that takes a single parameter (of whatever type the filter | ||
operates on) and returns a boolean. | ||
:return: A filter function of one argument that is the logical OR of the predicates for each of | ||
the comma-separated arguments. If the comma-separated list was prefixed by a '-', | ||
the sense of the filter is inverted. | ||
""" | ||
# NOTE: Do not inline this into create_filters above. A separate function is necessary | ||
# in order to capture the different closure on each invocation. | ||
modifier, param = _extract_modifier(predicate_param) | ||
predicates = map(predicate_factory, param.split(',')) | ||
def filt(x): | ||
return modifier(any(map(lambda pred: pred(x), predicates))) | ||
return filt | ||
|
||
|
||
def wrap_filters(filters): | ||
"""Returns a single filter that short-circuit ANDs the specified filters.""" | ||
def combined_filter(x): | ||
for filt in filters: | ||
if not filt(x): | ||
return False | ||
return True | ||
return combined_filter |
Oops, something went wrong.