match: simplify brittle predicate construction
authorMartin von Zweigbergk <martinvonz@gmail.com>
Fri, 19 Sep 2014 13:49:58 -0700
changeset 22513 ca709785caf2
parent 22512 6b6da715cb96
child 22514 48e4e47774bf
match: simplify brittle predicate construction In match.__init__(), we create the matchfn predicate by and-ing together the individual predicates for includes, excludes (negated) and patterns. Instead of the current set of nested if/else blocks, we can simplify by adding the predicates to a list and defining the overall predicate in a generic way based on the components. We can still optimize it for the 0-length and 1-length cases. This way, there is no combinatorial explosion to deal with if new component predicates are added, and there is less risk of getting the overall predicate wrong.
mercurial/match.py
--- a/mercurial/match.py	Tue Sep 23 14:45:23 2014 -0700
+++ b/mercurial/match.py	Fri Sep 19 13:49:58 2014 -0700
@@ -66,47 +66,39 @@
         self._ctx = ctx
         self._always = False
 
+        matchfns = []
         if include:
             kindpats = _normalize(include, 'glob', root, cwd, auditor)
             self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)')
+            matchfns.append(im)
         if exclude:
             kindpats = _normalize(exclude, 'glob', root, cwd, auditor)
             self.excludepat, em = _buildmatch(ctx, kindpats, '(?:/|$)')
+            matchfns.append(lambda f: not em(f))
         if exact:
             if isinstance(patterns, list):
                 self._files = patterns
             else:
                 self._files = list(patterns)
-            pm = self.exact
+            matchfns.append(self.exact)
         elif patterns:
             kindpats = _normalize(patterns, default, root, cwd, auditor)
             self._files = _roots(kindpats)
             self._anypats = self._anypats or _anypats(kindpats)
             self.patternspat, pm = _buildmatch(ctx, kindpats, '$')
+            matchfns.append(pm)
 
-        if patterns or exact:
-            if include:
-                if exclude:
-                    m = lambda f: im(f) and not em(f) and pm(f)
-                else:
-                    m = lambda f: im(f) and pm(f)
-            else:
-                if exclude:
-                    m = lambda f: not em(f) and pm(f)
-                else:
-                    m = pm
+        if not matchfns:
+            m = util.always
+            self._always = True
+        elif len(matchfns) == 1:
+            m = matchfns[0]
         else:
-            if include:
-                if exclude:
-                    m = lambda f: im(f) and not em(f)
-                else:
-                    m = im
-            else:
-                if exclude:
-                    m = lambda f: not em(f)
-                else:
-                    m = lambda f: True
-                    self._always = True
+            def m(f):
+                for matchfn in matchfns:
+                    if not matchfn(f):
+                        return False
+                return True
 
         self.matchfn = m
         self._fmap = set(self._files)