Skip to content

Commit

Permalink
Add and use batch forms of file matching calls.
Browse files Browse the repository at this point in the history
  • Loading branch information
stuhood committed Mar 14, 2018
1 parent f226371 commit c65a57d
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 28 deletions.
23 changes: 12 additions & 11 deletions src/python/pants/engine/legacy/address_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,21 @@ def scan_build_files(self, base_path):
return build_files_set

@staticmethod
def is_declaring_file(address, file_path):
if not BuildFile._is_buildfile_name(os.path.basename(file_path)):
return False

def any_is_declaring_file(address, file_paths):
try:
# A precise check for BuildFileAddress
return address.rel_path == file_path
return address.rel_path in file_paths
except AttributeError:
# NB: this will cause any BUILD file, whether it contains the address declaration or not to be
# considered the one that declared it. That's ok though, because the spec path should be enough
# information for debugging most of the time.
#
# TODO: remove this after https://github.com/pantsbuild/pants/issues/3925 lands
return os.path.dirname(file_path) == address.spec_path
pass
# NB: this will cause any BUILD file, whether it contains the address declaration or not to be
# considered the one that declared it. That's ok though, because the spec path should be enough
# information for debugging most of the time.
return any(address.spec_path == os.path.dirname(fp)
for fp in file_paths if BuildFile._is_buildfile_name(os.path.basename(fp)))

@staticmethod
def is_declaring_file(address, file_path):
return any_declaring_file(address, [file_path])

def addresses_in_spec_path(self, spec_path):
return self.scan_specs([SiblingAddresses(spec_path)])
Expand Down
19 changes: 11 additions & 8 deletions src/python/pants/engine/legacy/source_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from pants.build_graph.source_mapper import SourceMapper
from pants.engine.legacy.address_mapper import LegacyAddressMapper
from pants.engine.legacy.graph import HydratedTargets
from pants.source.filespec import matches_filespec
from pants.source.filespec import any_matches_filespec


def iter_resolve_and_parse_specs(rel_path, specs):
Expand Down Expand Up @@ -50,23 +50,26 @@ def _unique_dirs_for_sources(self, sources):
def target_addresses_for_source(self, source):
return list(self.iter_target_addresses_for_sources([source]))

def _match_source(self, source, fileset):
return fileset.matches(source) or matches_filespec(source, fileset.filespec)
def _match_sources(self, sources_set, fileset):
# NB: Deleted files can only be matched against the 'filespec' (ie, `PathGlobs`) for a target,
# so we don't actually call `fileset.matches` here.
# TODO: This call should be pushed down into the engine one way or another.
return any_matches_filespec(sources_set, fileset.filespec)

def _owns_source(self, source, legacy_target):
def _owns_any_source(self, sources_set, legacy_target):
"""Given a `HydratedTarget` instance, check if it owns the given source file."""
target_kwargs = legacy_target.adaptor.kwargs()

# Handle targets like `python_binary` which have a singular `source='main.py'` declaration.
target_source = target_kwargs.get('source')
if target_source:
path_from_build_root = os.path.join(legacy_target.adaptor.address.spec_path, target_source)
if path_from_build_root == source:
if path_from_build_root in sources_set:
return True

# Handle `sources`-declaring targets.
target_sources = target_kwargs.get('sources', [])
if target_sources and self._match_source(source, target_sources):
if target_sources and self._match_sources(sources_set, target_sources):
return True

return False
Expand All @@ -86,6 +89,6 @@ def iter_target_addresses_for_sources(self, sources):

for hydrated_target, legacy_address in six.iteritems(hydrated_target_to_address):
# Handle BUILD files.
if (any(LegacyAddressMapper.is_declaring_file(legacy_address, f) for f in sources_set) or
any(self._owns_source(source, hydrated_target) for source in sources_set)):
if (LegacyAddressMapper.any_is_declaring_file(legacy_address, sources_set) or
self._owns_any_source(sources_set, hydrated_target)):
yield legacy_address
30 changes: 21 additions & 9 deletions src/python/pants/source/filespec.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,28 @@ def glob_to_regex(pattern):
return ''.join(out)


def globs_matches(path, patterns):
return any(re.match(glob_to_regex(pattern), path) for pattern in patterns)
def globs_matches(paths, patterns, exclude_patterns):
def excluded(path):
if excluded.regexes is None:
excluded.regexes = [re.compile(glob_to_regex(ex)) for ex in exclude_patterns]
return any(ex.match(path) for ex in excluded.regexes)
excluded.regexes = None
for pattern in patterns:
regex = re.compile(glob_to_regex(pattern))
for path in paths:
if regex.match(path) and not excluded(path):
return True
return False


def matches_filespec(path, spec):
if spec is None:
return False
if not globs_matches(path, spec.get('globs', [])):
return any_matches_filespec([path], spec)


def any_matches_filespec(paths, spec):
if not paths or not spec:
return False
for spec in spec.get('exclude', []):
if matches_filespec(path, spec):
return False
return True
exclude_patterns = []
for exclude_spec in spec.get('exclude', []):
exclude_patterns.extend(exclude_spec.get('globs', []))
return globs_matches(paths, spec.get('globs', []), exclude_patterns)

0 comments on commit c65a57d

Please sign in to comment.