Patchwork [1,of,7] match: replace match class by match function (API)

login
register
mail settings
Submitter via Mercurial-devel
Date May 22, 2017, 6:16 a.m.
Message ID <13379def135e9a24b784.1495433761@martinvonz.svl.corp.google.com>
Download mbox | patch
Permalink /patch/20817/
State Accepted
Headers show

Comments

via Mercurial-devel - May 22, 2017, 6:16 a.m.
# HG changeset patch
# User Martin von Zweigbergk <martinvonz@google.com>
# Date 1494655901 25200
#      Fri May 12 23:11:41 2017 -0700
# Node ID 13379def135e9a24b784b0d8570036f7b12449f6
# Parent  4e51b2a99847904f1cc5a9c74784f19d69e829d0
match: replace match class by match function (API)

The matcher class is getting hard to understand. It will be easier to
follow if we can break it up into simpler matchers that we then
compose. I'm hoping to have one matcher that accepts regular
(non-include) patterns, one for exact file matches, one that always
matches (and maybe one that never does) and then compose them by
intersection and difference.

This patch takes a simple but important step towards that goal by
making match.match() a function (and renaming the matcher class itself
from "match" to "matcher"). The new function will eventually be
responsible for creating the simple matchers and composing them.

icasefsmatcher similarly gets a factory function (called
"icasefsmatch"). I also moved the other factory functions nearby.
Yuya Nishihara - May 22, 2017, 2:34 p.m.
On Sun, 21 May 2017 23:16:01 -0700, Martin von Zweigbergk via Mercurial-devel wrote:
> # HG changeset patch
> # User Martin von Zweigbergk <martinvonz@google.com>
> # Date 1494655901 25200
> #      Fri May 12 23:11:41 2017 -0700
> # Node ID 13379def135e9a24b784b0d8570036f7b12449f6
> # Parent  4e51b2a99847904f1cc5a9c74784f19d69e829d0
> match: replace match class by match function (API)

Great refactoring overall. Queued, thanks.

Patch

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1595,7 +1595,7 @@ 
         # to actual case in the filesystem.
         matcherfunc = matchmod.match
         if not util.fscasesensitive(r.root):
-            matcherfunc = matchmod.icasefsmatcher
+            matcherfunc = matchmod.icasefsmatch
         return matcherfunc(r.root, r.getcwd(), pats,
                            include, exclude, default,
                            auditor=r.auditor, ctx=self,
diff --git a/mercurial/match.py b/mercurial/match.py
--- a/mercurial/match.py
+++ b/mercurial/match.py
@@ -84,39 +84,71 @@ 
             return False
     return True
 
-class match(object):
+def match(root, cwd, patterns, include=None, exclude=None, default='glob',
+          exact=False, auditor=None, ctx=None, listsubrepos=False, warn=None,
+          badfn=None):
+    """build an object to match a set of file patterns
+
+    arguments:
+    root - the canonical root of the tree you're matching against
+    cwd - the current working directory, if relevant
+    patterns - patterns to find
+    include - patterns to include (unless they are excluded)
+    exclude - patterns to exclude (even if they are included)
+    default - if a pattern in patterns has no explicit type, assume this one
+    exact - patterns are actually filenames (include/exclude still apply)
+    warn - optional function used for printing warnings
+    badfn - optional bad() callback for this matcher instead of the default
+
+    a pattern is one of:
+    'glob:<glob>' - a glob relative to cwd
+    're:<regexp>' - a regular expression
+    'path:<path>' - a path relative to repository root, which is matched
+                    recursively
+    'rootfilesin:<path>' - a path relative to repository root, which is
+                    matched non-recursively (will not match subdirectories)
+    'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
+    'relpath:<path>' - a path relative to cwd
+    'relre:<regexp>' - a regexp that needn't match the start of a name
+    'set:<fileset>' - a fileset expression
+    'include:<path>' - a file of patterns to read and include
+    'subinclude:<path>' - a file of patterns to match against files under
+                          the same directory
+    '<something>' - a pattern of the specified default type
+    """
+    return matcher(root, cwd, patterns, include=include, exclude=exclude,
+                   default=default, exact=exact, auditor=auditor, ctx=ctx,
+                   listsubrepos=listsubrepos, warn=warn, badfn=badfn)
+
+def icasefsmatch(root, cwd, patterns, include=None, exclude=None,
+                 default='glob', auditor=None, ctx=None,
+                 listsubrepos=False, badfn=None):
+    """A matcher for wdir on case insensitive filesystems, which normalizes the
+    given patterns to the case in the filesystem.
+    """
+    return icasefsmatcher(root, cwd, patterns, include=include, exclude=exclude,
+                          default=default, auditor=auditor, ctx=ctx,
+                          listsubrepos=listsubrepos, badfn=badfn)
+
+def exact(root, cwd, files, badfn=None):
+    return match(root, cwd, files, exact=True, badfn=badfn)
+
+def always(root, cwd):
+    return match(root, cwd, [])
+
+def badmatch(match, badfn):
+    """Make a copy of the given matcher, replacing its bad method with the given
+    one.
+    """
+    m = copy.copy(match)
+    m.bad = badfn
+    return m
+
+class matcher(object):
+
     def __init__(self, root, cwd, patterns, include=None, exclude=None,
                  default='glob', exact=False, auditor=None, ctx=None,
                  listsubrepos=False, warn=None, badfn=None):
-        """build an object to match a set of file patterns
-
-        arguments:
-        root - the canonical root of the tree you're matching against
-        cwd - the current working directory, if relevant
-        patterns - patterns to find
-        include - patterns to include (unless they are excluded)
-        exclude - patterns to exclude (even if they are included)
-        default - if a pattern in patterns has no explicit type, assume this one
-        exact - patterns are actually filenames (include/exclude still apply)
-        warn - optional function used for printing warnings
-        badfn - optional bad() callback for this matcher instead of the default
-
-        a pattern is one of:
-        'glob:<glob>' - a glob relative to cwd
-        're:<regexp>' - a regular expression
-        'path:<path>' - a path relative to repository root, which is matched
-                        recursively
-        'rootfilesin:<path>' - a path relative to repository root, which is
-                        matched non-recursively (will not match subdirectories)
-        'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
-        'relpath:<path>' - a path relative to cwd
-        'relre:<regexp>' - a regexp that needn't match the start of a name
-        'set:<fileset>' - a fileset expression
-        'include:<path>' - a file of patterns to read and include
-        'subinclude:<path>' - a file of patterns to match against files under
-                              the same directory
-        '<something>' - a pattern of the specified default type
-        """
         if include is None:
             include = []
         if exclude is None:
@@ -331,21 +363,7 @@ 
             kindpats.append((kind, pat, ''))
         return kindpats
 
-def exact(root, cwd, files, badfn=None):
-    return match(root, cwd, files, exact=True, badfn=badfn)
-
-def always(root, cwd):
-    return match(root, cwd, [])
-
-def badmatch(match, badfn):
-    """Make a copy of the given matcher, replacing its bad method with the given
-    one.
-    """
-    m = copy.copy(match)
-    m.bad = badfn
-    return m
-
-class subdirmatcher(match):
+class subdirmatcher(matcher):
     """Adapt a matcher to work on a subdirectory only.
 
     The paths are remapped to remove/insert the path as needed:
@@ -416,10 +434,7 @@ 
             dir = self._path + "/" + dir
         return self._matcher.visitdir(dir)
 
-class icasefsmatcher(match):
-    """A matcher for wdir on case insensitive filesystems, which normalizes the
-    given patterns to the case in the filesystem.
-    """
+class icasefsmatcher(matcher):
 
     def __init__(self, root, cwd, patterns, include, exclude, default, auditor,
                  ctx, listsubrepos=False, badfn=None):