fileset: prescan parse tree to optimize status usage
authorMatt Mackall <mpm@selenic.com>
Sat, 18 Jun 2011 16:53:49 -0500
changeset 14678 5ef7b87530f6
parent 14677 2a758ffc821e
child 14679 e141e1cee0cc
fileset: prescan parse tree to optimize status usage We only call status if needed to avoid walking the working directory or comparing manifests. Similarly, we scan for whether unknown or ignored files are mentioned so we can include them.
mercurial/fileset.py
--- a/mercurial/fileset.py	Sat Jun 18 16:53:49 2011 -0500
+++ b/mercurial/fileset.py	Sat Jun 18 16:53:49 2011 -0500
@@ -204,21 +204,7 @@
         self.ctx = ctx
         self.subset = subset
         self._status = status
-        if status is None:
-            # desperately wants optimizing
-            r = self.ctx._repo
-            self._status = r.status(self.ctx.p1(), self.ctx,
-                                    unknown=True, ignored=True, clean=True)
-        if subset is None:
-            self.subset = []
-            for c in self._status:
-                self.subset.extend(c)
     def status(self):
-        if not self._status:
-            r = self.ctx._repo
-            # also wants optimizing
-            self._status = r.status(self.ctx.p1(), self.ctx,
-                                    unknown=True, ignored=True, clean=True)
         return self._status
     def matcher(self, patterns):
         return self.ctx.match(patterns)
@@ -227,8 +213,35 @@
     def narrow(self, files):
         return matchctx(self.ctx, self.filter(files), self._status)
 
+def _intree(funcs, tree):
+    if isinstance(tree, tuple):
+        if tree[0] == 'func' and tree[1][0] == 'symbol':
+            if tree[1][1] in funcs:
+                return True
+        for s in tree[1:]:
+            if _intree(funcs, s):
+                return True
+    return False
+
 def getfileset(ctx, expr):
     tree, pos = parse(expr)
     if (pos != len(expr)):
         raise error.ParseError("invalid token", pos)
-    return getset(matchctx(ctx), tree)
+
+    # do we need status info?
+    if _intree(['modified', 'added', 'removed', 'deleted',
+                'unknown', 'ignored', 'clean'], tree):
+        unknown = _intree(['unknown'], tree)
+        ignored = _intree(['ignored'], tree)
+
+        r = ctx._repo
+        status = r.status(ctx.p1(), ctx,
+                          unknown=unknown, ignored=ignored, clean=True)
+        subset = []
+        for c in status:
+            subset.extend(c)
+    else:
+        status = None
+        subset = ctx.walk(ctx.match([]))
+
+    return getset(matchctx(ctx, subset, status), tree)