Mercurial > hgrepos > Python > apps > py-cutils
view cutils/util/fnmatch.py @ 302:bf88323d6bf7
treesum: Implement --exclude/--include.
- Filtering
- Document in output
- Handle in the "info" command
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Wed, 05 Mar 2025 10:07:44 +0100 |
| parents | 1fc117f5f9a1 |
| children | dc1f08937621 |
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 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, } VISIT_DEFAULT = True # Overall default value for visiting def __init__(self, matchers): super(FnMatcher, self).__init__() self._matchers = matchers @classmethod def build_from_commandline_patterns(klass, filter_definitions): matchers = [] for action, kpattern in filter_definitions: 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): visit = self.VISIT_DEFAULT for action, kind, matcher, orig_pattern in self._matchers: res = matcher(fn) if res: if action == "include": visit = True elif action == "exclude": visit = False else: raise RuntimeError("unknown action: {}".format(action)) return visit def definitions(self): for action, kind, matcher, orig_pattern in self._matchers: yield (action, kind, orig_pattern)
