Mercurial > hgrepos > Python > apps > py-cutils
view cutils/util/fnmatch.py @ 308:652870b20f9e
treesum: Implement --accept-treesum: trust a treesum-file for a directory checksum
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sat, 08 Mar 2025 04:49:06 +0100 |
| parents | 6c212e407524 |
| children | f5f54b9c3552 |
line wrap: on
line source
# -*- coding: utf-8 -*- # :- # :Copyright: (c) 2020-2025 Franz Glasner # :License: BSD-3-Clause # :- r"""File name matching. """ from __future__ import print_function, absolute_import __all__ = ["FnMatcher"] import re from . import PY2 from . import glob HELP_DESCRIPTION = """\ PATTERNs ======== glob: case-sensitive, anchored at the begin and end iglob: case-insensitive variant of "glob" re: regular expression path: plain text example (rooted), can be a file or a directory or a prefix thereof fullpath: exactly a single full path (file or directory), relative to the root of the tree """ def glob_factory(pattern): cpat = re.compile( # automatically anchored "\\A{}\\Z".format(glob.glob_to_regexp(pattern)), re.DOTALL) def _glob_matcher(s): return cpat.search(s) is not None return _glob_matcher def iglob_factory(pattern): cpat = re.compile( # automatically anchored "\\A{}\\Z".format(glob.glob_to_regexp(pattern)), re.DOTALL | re.IGNORECASE) def _iglob_matcher(s): return cpat.search(s) is not None return _iglob_matcher def re_factory(pattern): cpat = re.compile(pattern, re.DOTALL) def _re_matcher(s): return cpat.search(s) is not None return _re_matcher def path_factory(pattern): def _path_matcher(s): return s.startswith(pattern) return _path_matcher def fullpath_factory(pattern): def _fullpath_matcher(s): return s == pattern return _fullpath_matcher class FnMatcher(object): _registry = { "glob": glob_factory, "iglob": iglob_factory, "re": re_factory, "path": path_factory, "fullpath": fullpath_factory, } def __init__(self, matchers): super(FnMatcher, self).__init__() self._matchers = matchers @classmethod def build_from_commandline_patterns(klass, filter_definitions): matchers = [] if filter_definitions: for action, kpattern in filter_definitions: assert action in ("include", "exclude", "accept-treesum") kind, sep, pattern = kpattern.partition(':') if not sep: # use the default kind = "glob" pattern = kpattern factory = klass._registry.get(kind, None) if not factory: raise RuntimeError("unknown pattern kind: {}".format(kind)) matchers.append((action, kind, factory(pattern), pattern)) return klass(matchers) def shall_visit(self, fn, default=True): visit = default for action, kind, matcher, orig_pattern in self._matchers: if matcher(fn): if action == "include": visit = True elif action in ("exclude", "accept-treesum"): visit = False else: raise RuntimeError("unknown action: {}".format(action)) return visit def shall_accept_treesum(self, fn, default=False): accept = default for action, kind, matcher, orig_pattern in self._matchers: if action == "accept-treesum": if matcher(fn): accept = True elif action in ("include", "exclude"): pass else: raise RuntimeError("unknown action: {}".format(action)) return accept def definitions(self): for action, kind, matcher, orig_pattern in self._matchers: yield (action, kind, orig_pattern) def __bool__(self): return bool(self._matchers) if PY2: __nonzero__ = __bool__
