mirror of
https://github.com/thegeeklab/ansible-later.git
synced 2024-11-16 10:00:39 +00:00
138 lines
4.5 KiB
Python
138 lines
4.5 KiB
Python
|
# encoding: utf-8
|
||
|
"""
|
||
|
This module provides an object oriented interface for pattern matching
|
||
|
of files.
|
||
|
"""
|
||
|
|
||
|
from . import util
|
||
|
from .compat import collection_type, iterkeys, izip_longest, string_types, unicode
|
||
|
|
||
|
|
||
|
class PathSpec(object):
|
||
|
"""
|
||
|
The :class:`PathSpec` class is a wrapper around a list of compiled
|
||
|
:class:`.Pattern` instances.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, patterns):
|
||
|
"""
|
||
|
Initializes the :class:`PathSpec` instance.
|
||
|
|
||
|
*patterns* (:class:`~collections.abc.Collection` or :class:`~collections.abc.Iterable`)
|
||
|
yields each compiled pattern (:class:`.Pattern`).
|
||
|
"""
|
||
|
|
||
|
self.patterns = patterns if isinstance(patterns, collection_type) else list(patterns)
|
||
|
"""
|
||
|
*patterns* (:class:`~collections.abc.Collection` of :class:`.Pattern`)
|
||
|
contains the compiled patterns.
|
||
|
"""
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
"""
|
||
|
Tests the equality of this path-spec with *other* (:class:`PathSpec`)
|
||
|
by comparing their :attr:`~PathSpec.patterns` attributes.
|
||
|
"""
|
||
|
if isinstance(other, PathSpec):
|
||
|
paired_patterns = izip_longest(self.patterns, other.patterns)
|
||
|
return all(a == b for a, b in paired_patterns)
|
||
|
else:
|
||
|
return NotImplemented
|
||
|
|
||
|
def __len__(self):
|
||
|
"""
|
||
|
Returns the number of compiled patterns this path-spec contains
|
||
|
(:class:`int`).
|
||
|
"""
|
||
|
return len(self.patterns)
|
||
|
|
||
|
@classmethod
|
||
|
def from_lines(cls, pattern_factory, lines):
|
||
|
"""
|
||
|
Compiles the pattern lines.
|
||
|
|
||
|
*pattern_factory* can be either the name of a registered pattern
|
||
|
factory (:class:`str`), or a :class:`~collections.abc.Callable` used
|
||
|
to compile patterns. It must accept an uncompiled pattern (:class:`str`)
|
||
|
and return the compiled pattern (:class:`.Pattern`).
|
||
|
|
||
|
*lines* (:class:`~collections.abc.Iterable`) yields each uncompiled
|
||
|
pattern (:class:`str`). This simply has to yield each line so it can
|
||
|
be a :class:`file` (e.g., from :func:`open` or :class:`io.StringIO`)
|
||
|
or the result from :meth:`str.splitlines`.
|
||
|
|
||
|
Returns the :class:`PathSpec` instance.
|
||
|
"""
|
||
|
if isinstance(pattern_factory, string_types):
|
||
|
pattern_factory = util.lookup_pattern(pattern_factory)
|
||
|
if not callable(pattern_factory):
|
||
|
raise TypeError("pattern_factory:{0!r} is not callable.".format(pattern_factory))
|
||
|
|
||
|
if isinstance(lines, (bytes, unicode)):
|
||
|
raise TypeError("lines:{0!r} is not an iterable.".format(lines))
|
||
|
|
||
|
lines = [pattern_factory(line) for line in lines if line]
|
||
|
return cls(lines)
|
||
|
|
||
|
def match_file(self, file, separators=None):
|
||
|
"""
|
||
|
Matches the file to this path-spec.
|
||
|
|
||
|
*file* (:class:`str`) is the file path to be matched against
|
||
|
:attr:`self.patterns <PathSpec.patterns>`.
|
||
|
|
||
|
*separators* (:class:`~collections.abc.Collection` of :class:`str`)
|
||
|
optionally contains the path separators to normalize. See
|
||
|
:func:`~pathspec.util.normalize_file` for more information.
|
||
|
|
||
|
Returns :data:`True` if *file* matched; otherwise, :data:`False`.
|
||
|
"""
|
||
|
norm_file = util.normalize_file(file, separators=separators)
|
||
|
return util.match_file(self.patterns, norm_file)
|
||
|
|
||
|
def match_files(self, files, separators=None):
|
||
|
"""
|
||
|
Matches the files to this path-spec.
|
||
|
|
||
|
*files* (:class:`~collections.abc.Iterable` of :class:`str`) contains
|
||
|
the file paths to be matched against :attr:`self.patterns
|
||
|
<PathSpec.patterns>`.
|
||
|
|
||
|
*separators* (:class:`~collections.abc.Collection` of :class:`str`;
|
||
|
or :data:`None`) optionally contains the path separators to
|
||
|
normalize. See :func:`~pathspec.util.normalize_file` for more
|
||
|
information.
|
||
|
|
||
|
Returns the matched files (:class:`~collections.abc.Iterable` of
|
||
|
:class:`str`).
|
||
|
"""
|
||
|
if isinstance(files, (bytes, unicode)):
|
||
|
raise TypeError("files:{0!r} is not an iterable.".format(files))
|
||
|
|
||
|
file_map = util.normalize_files(files, separators=separators)
|
||
|
matched_files = util.match_files(self.patterns, iterkeys(file_map))
|
||
|
for path in matched_files:
|
||
|
yield file_map[path]
|
||
|
|
||
|
def match_tree(self, root, on_error=None, follow_links=None):
|
||
|
"""
|
||
|
Walks the specified root path for all files and matches them to this
|
||
|
path-spec.
|
||
|
|
||
|
*root* (:class:`str`) is the root directory to search for files.
|
||
|
|
||
|
*on_error* (:class:`~collections.abc.Callable` or :data:`None`)
|
||
|
optionally is the error handler for file-system exceptions. See
|
||
|
:func:`~pathspec.util.iter_tree` for more information.
|
||
|
|
||
|
|
||
|
*follow_links* (:class:`bool` or :data:`None`) optionally is whether
|
||
|
to walk symbolik links that resolve to directories. See
|
||
|
:func:`~pathspec.util.iter_tree` for more information.
|
||
|
|
||
|
Returns the matched files (:class:`~collections.abc.Iterable` of
|
||
|
:class:`str`).
|
||
|
"""
|
||
|
files = util.iter_tree(root, on_error=on_error, follow_links=follow_links)
|
||
|
return self.match_files(files)
|