changeset 14678:5ef7b87530f6

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.
author Matt Mackall <mpm@selenic.com>
date Sat, 18 Jun 2011 16:53:49 -0500
parents 2a758ffc821e
children e141e1cee0cc
files mercurial/fileset.py
diffstat 1 files changed, 28 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- 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)