changeset 9662:f3d60543924f

walkchangerevs: move 'add' to callback Now walkchangerevs is a simple iterator over contexts
author Matt Mackall <mpm@selenic.com>
date Thu, 29 Oct 2009 17:07:51 -0500
parents c4f6c02e33c4
children 4164a17e7126
files hgext/churn.py mercurial/cmdutil.py mercurial/commands.py
diffstat 3 files changed, 114 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/churn.py	Wed Oct 28 23:59:18 2009 +0900
+++ b/hgext/churn.py	Thu Oct 29 17:07:51 2009 -0500
@@ -54,13 +54,10 @@
         df = util.matchdate(opts['date'])
 
     m = cmdutil.match(repo, pats, opts)
-    for st, ctx, fns in cmdutil.walkchangerevs(ui, repo, m, opts):
-        if not st == 'add':
-            continue
-
+    def prep(ctx, fns):
         rev = ctx.rev()
         if df and not df(ctx.date()[0]): # doesn't match date format
-            continue
+            return
 
         key = getkey(ctx)
         key = amap.get(key, key) # alias remap
@@ -70,7 +67,7 @@
             parents = ctx.parents()
             if len(parents) > 1:
                 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
-                continue
+                return
 
             ctx1 = parents[0]
             lines = changedlines(ui, repo, ctx1, ctx, fns)
@@ -84,6 +81,9 @@
                 ui.write("\r" + _("generating stats: %d%%") % pct)
                 sys.stdout.flush()
 
+    for ctx in cmdutil.walkchangerevs(ui, repo, m, opts, prep):
+        continue
+
     if opts.get('progress'):
         ui.write("\r")
         sys.stdout.flush()
--- a/mercurial/cmdutil.py	Wed Oct 28 23:59:18 2009 +0900
+++ b/mercurial/cmdutil.py	Thu Oct 29 17:07:51 2009 -0500
@@ -1023,23 +1023,24 @@
 def finddate(ui, repo, date):
     """Find the tipmost changeset that matches the given date spec"""
     df = util.matchdate(date)
-    get = util.cachefunc(lambda r: repo[r])
     m = matchall(repo)
     results = {}
-    for st, rev, fns in walkchangerevs(ui, repo, m, get, {'rev':None}):
-        if st == 'add':
-            d = get(rev).date()
-            if df(d[0]):
-                results[rev] = d
-        elif st == 'iter':
-            if rev in results:
-                ui.status(_("Found revision %s from %s\n") %
-                          (rev, util.datestr(results[rev])))
-                return str(rev)
+
+    def prep(ctx, fns):
+        d = ctx.date()
+        if df(d[0]):
+            results[rev] = d
+
+    for ctx in walkchangerevs(ui, repo, m, {'rev':None}, prep):
+        rev = ctx.rev()
+        if rev in results:
+            ui.status(_("Found revision %s from %s\n") %
+                      (rev, util.datestr(results[rev])))
+            return str(rev)
 
     raise util.Abort(_("revision matching date not found"))
 
-def walkchangerevs(ui, repo, match, opts):
+def walkchangerevs(ui, repo, match, opts, prepare):
     '''Iterate over files and the revs in which they changed.
 
     Callers most commonly need to iterate backwards over the history
@@ -1050,15 +1051,9 @@
     window, we first walk forwards to gather data, then in the desired
     order (usually backwards) to display it.
 
-    This function returns an iterator. The iterator yields 3-tuples.
-    They will be of one of the following forms:
-
-    "add", rev, fns: out-of-order traversal of the given filenames
-    fns, which changed during revision rev - use to gather data for
-    possible display
-
-    "iter", rev, None: in-order traversal of the revs earlier iterated
-    over with "add" - use to display data'''
+    This function returns an iterator yielding contexts. Before
+    yielding each context, the iterator will first call the prepare
+    function on each context in the window in forward order.'''
 
     def increasing_windows(start, end, windowsize=8, sizelimit=512):
         if start < end:
@@ -1225,9 +1220,9 @@
                             if match(f):
                                 yield f
                     fns = fns_generator()
-                yield 'add', ctx, fns
+                prepare(ctx, fns)
             for rev in nrevs:
-                yield 'iter', change(rev), None
+                yield change(rev)
     return iterate()
 
 def commit(ui, repo, commitfunc, pats, opts):
--- a/mercurial/commands.py	Wed Oct 28 23:59:18 2009 +0900
+++ b/mercurial/commands.py	Thu Oct 29 17:07:51 2009 -0500
@@ -1302,61 +1302,62 @@
     matchfn = cmdutil.match(repo, pats, opts)
     found = False
     follow = opts.get('follow')
-    for st, ctx, fns in cmdutil.walkchangerevs(ui, repo, matchfn, opts):
-        if st == 'add':
-            rev = ctx.rev()
-            pctx = ctx.parents()[0]
-            parent = pctx.rev()
-            matches.setdefault(rev, {})
-            matches.setdefault(parent, {})
-            files = revfiles.setdefault(rev, [])
-            for fn in fns:
-                flog = getfile(fn)
+
+    def prep(ctx, fns):
+        rev = ctx.rev()
+        pctx = ctx.parents()[0]
+        parent = pctx.rev()
+        matches.setdefault(rev, {})
+        matches.setdefault(parent, {})
+        files = revfiles.setdefault(rev, [])
+        for fn in fns:
+            flog = getfile(fn)
+            try:
+                fnode = ctx.filenode(fn)
+            except error.LookupError:
+                continue
+
+            copied = flog.renamed(fnode)
+            copy = follow and copied and copied[0]
+            if copy:
+                copies.setdefault(rev, {})[fn] = copy
+            if fn in skip:
+                if copy:
+                    skip[copy] = True
+                continue
+            files.append(fn)
+
+            if fn not in matches[rev]:
+                grepbody(fn, rev, flog.read(fnode))
+
+            pfn = copy or fn
+            if pfn not in matches[parent]:
                 try:
-                    fnode = ctx.filenode(fn)
+                    fnode = pctx.filenode(pfn)
+                    grepbody(pfn, parent, flog.read(fnode))
                 except error.LookupError:
-                    continue
-
-                copied = flog.renamed(fnode)
-                copy = follow and copied and copied[0]
+                    pass
+
+    for ctx in cmdutil.walkchangerevs(ui, repo, matchfn, opts, prep):
+        rev = ctx.rev()
+        parent = ctx.parents()[0].rev()
+        for fn in sorted(revfiles.get(rev, [])):
+            states = matches[rev][fn]
+            copy = copies.get(rev, {}).get(fn)
+            if fn in skip:
                 if copy:
-                    copies.setdefault(rev, {})[fn] = copy
-                if fn in skip:
+                    skip[copy] = True
+                continue
+            pstates = matches.get(parent, {}).get(copy or fn, [])
+            if pstates or states:
+                r = display(fn, ctx, pstates, states)
+                found = found or r
+                if r and not opts.get('all'):
+                    skip[fn] = True
                     if copy:
                         skip[copy] = True
-                    continue
-                files.append(fn)
-
-                if fn not in matches[rev]:
-                    grepbody(fn, rev, flog.read(fnode))
-
-                pfn = copy or fn
-                if pfn not in matches[parent]:
-                    try:
-                        fnode = pctx.filenode(pfn)
-                        grepbody(pfn, parent, flog.read(fnode))
-                    except error.LookupError:
-                        pass
-        elif st == 'iter':
-            rev = ctx.rev()
-            parent = ctx.parents()[0].rev()
-            for fn in sorted(revfiles.get(rev, [])):
-                states = matches[rev][fn]
-                copy = copies.get(rev, {}).get(fn)
-                if fn in skip:
-                    if copy:
-                        skip[copy] = True
-                    continue
-                pstates = matches.get(parent, {}).get(copy or fn, [])
-                if pstates or states:
-                    r = display(fn, ctx, pstates, states)
-                    found = found or r
-                    if r and not opts.get('all'):
-                        skip[fn] = True
-                        if copy:
-                            skip[copy] = True
-            del matches[rev]
-            del revfiles[rev]
+        del matches[rev]
+        del revfiles[rev]
 
 def heads(ui, repo, *branchrevs, **opts):
     """show current repository heads or show branch heads
@@ -2037,50 +2038,46 @@
     only_branches = opts.get('only_branch')
 
     displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
-    for st, ctx, fns in cmdutil.walkchangerevs(ui, repo, matchfn, opts):
+    def prep(ctx, fns):
         rev = ctx.rev()
-        if st == 'add':
-            parents = [p for p in repo.changelog.parentrevs(rev)
-                       if p != nullrev]
-            if opts.get('no_merges') and len(parents) == 2:
-                continue
-            if opts.get('only_merges') and len(parents) != 2:
-                continue
-
-            if only_branches and ctx.branch() not in only_branches:
-                continue
-
-            if df and not df(ctx.date()[0]):
-                continue
-
-            if opts.get('keyword'):
-                miss = 0
-                for k in [kw.lower() for kw in opts['keyword']]:
-                    if not (k in ctx.user().lower() or
-                            k in ctx.description().lower() or
-                            k in " ".join(ctx.files()).lower()):
-                        miss = 1
-                        break
-                if miss:
-                    continue
-
-            if opts['user']:
-                if not [k for k in opts['user'] if k in ctx.user()]:
-                    continue
-
-            copies = []
-            if opts.get('copies') and rev:
-                for fn in ctx.files():
-                    rename = getrenamed(fn, rev)
-                    if rename:
-                        copies.append((fn, rename[0]))
-
-            displayer.show(ctx, copies=copies)
-
-        elif st == 'iter':
-            if count == limit: break
-
-            if displayer.flush(rev):
+        parents = [p for p in repo.changelog.parentrevs(rev)
+                   if p != nullrev]
+        if opts.get('no_merges') and len(parents) == 2:
+            return
+        if opts.get('only_merges') and len(parents) != 2:
+            return
+        if only_branches and ctx.branch() not in only_branches:
+            return
+        if df and not df(ctx.date()[0]):
+            return
+
+        if opts.get('keyword'):
+            miss = 0
+            for k in [kw.lower() for kw in opts['keyword']]:
+                if not (k in ctx.user().lower() or
+                        k in ctx.description().lower() or
+                        k in " ".join(ctx.files()).lower()):
+                    miss = 1
+                    break
+            if miss:
+                return
+
+        if opts['user']:
+            if not [k for k in opts['user'] if k in ctx.user()]:
+                return
+
+        copies = []
+        if opts.get('copies') and rev:
+            for fn in ctx.files():
+                rename = getrenamed(fn, rev)
+                if rename:
+                    copies.append((fn, rename[0]))
+
+        displayer.show(ctx, copies=copies)
+
+    for ctx in cmdutil.walkchangerevs(ui, repo, matchfn, opts, prep):
+        if count != limit:
+            if displayer.flush(ctx.rev()):
                 count += 1
 
 def manifest(ui, repo, node=None, rev=None):