diff mercurial/commands.py @ 3650:731e739b8659

move walkchangerevs to cmdutils
author Matt Mackall <mpm@selenic.com>
date Wed, 15 Nov 2006 15:51:58 -0600
parents e50891e461e4
children 6389205291c6
line wrap: on
line diff
--- a/mercurial/commands.py	Wed Nov 15 15:51:58 2006 -0600
+++ b/mercurial/commands.py	Wed Nov 15 15:51:58 2006 -0600
@@ -49,200 +49,6 @@
                              (logfile, inst.strerror))
     return message
 
-def walkchangerevs(ui, repo, pats, change, opts):
-    '''Iterate over files and the revs they changed in.
-
-    Callers most commonly need to iterate backwards over the history
-    it is interested in.  Doing so has awful (quadratic-looking)
-    performance, so we use iterators in a "windowed" way.
-
-    We walk a window of revisions in the desired order.  Within the
-    window, we first walk forwards to gather data, then in the desired
-    order (usually backwards) to display it.
-
-    This function returns an (iterator, matchfn) tuple. The iterator
-    yields 3-tuples. They will be of one of the following forms:
-
-    "window", incrementing, lastrev: stepping through a window,
-    positive if walking forwards through revs, last rev in the
-    sequence iterated over - use to reset state for the current window
-
-    "add", rev, fns: out-of-order traversal of the given file names
-    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'''
-
-    def increasing_windows(start, end, windowsize=8, sizelimit=512):
-        if start < end:
-            while start < end:
-                yield start, min(windowsize, end-start)
-                start += windowsize
-                if windowsize < sizelimit:
-                    windowsize *= 2
-        else:
-            while start > end:
-                yield start, min(windowsize, start-end-1)
-                start -= windowsize
-                if windowsize < sizelimit:
-                    windowsize *= 2
-
-    files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
-    follow = opts.get('follow') or opts.get('follow_first')
-
-    if repo.changelog.count() == 0:
-        return [], matchfn
-
-    if follow:
-        defrange = '%s:0' % repo.changectx().rev()
-    else:
-        defrange = 'tip:0'
-    revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange])
-    wanted = {}
-    slowpath = anypats
-    fncache = {}
-
-    if not slowpath and not files:
-        # No files, no patterns.  Display all revs.
-        wanted = dict.fromkeys(revs)
-    copies = []
-    if not slowpath:
-        # Only files, no patterns.  Check the history of each file.
-        def filerevgen(filelog, node):
-            cl_count = repo.changelog.count()
-            if node is None:
-                last = filelog.count() - 1
-            else:
-                last = filelog.rev(node)
-            for i, window in increasing_windows(last, nullrev):
-                revs = []
-                for j in xrange(i - window, i + 1):
-                    n = filelog.node(j)
-                    revs.append((filelog.linkrev(n),
-                                 follow and filelog.renamed(n)))
-                revs.reverse()
-                for rev in revs:
-                    # only yield rev for which we have the changelog, it can
-                    # happen while doing "hg log" during a pull or commit
-                    if rev[0] < cl_count:
-                        yield rev
-        def iterfiles():
-            for filename in files:
-                yield filename, None
-            for filename_node in copies:
-                yield filename_node
-        minrev, maxrev = min(revs), max(revs)
-        for file_, node in iterfiles():
-            filelog = repo.file(file_)
-            # A zero count may be a directory or deleted file, so
-            # try to find matching entries on the slow path.
-            if filelog.count() == 0:
-                slowpath = True
-                break
-            for rev, copied in filerevgen(filelog, node):
-                if rev <= maxrev:
-                    if rev < minrev:
-                        break
-                    fncache.setdefault(rev, [])
-                    fncache[rev].append(file_)
-                    wanted[rev] = 1
-                    if follow and copied:
-                        copies.append(copied)
-    if slowpath:
-        if follow:
-            raise util.Abort(_('can only follow copies/renames for explicit '
-                               'file names'))
-
-        # The slow path checks files modified in every changeset.
-        def changerevgen():
-            for i, window in increasing_windows(repo.changelog.count()-1,
-                                                nullrev):
-                for j in xrange(i - window, i + 1):
-                    yield j, change(j)[3]
-
-        for rev, changefiles in changerevgen():
-            matches = filter(matchfn, changefiles)
-            if matches:
-                fncache[rev] = matches
-                wanted[rev] = 1
-
-    class followfilter:
-        def __init__(self, onlyfirst=False):
-            self.startrev = nullrev
-            self.roots = []
-            self.onlyfirst = onlyfirst
-
-        def match(self, rev):
-            def realparents(rev):
-                if self.onlyfirst:
-                    return repo.changelog.parentrevs(rev)[0:1]
-                else:
-                    return filter(lambda x: x != nullrev,
-                                  repo.changelog.parentrevs(rev))
-
-            if self.startrev == nullrev:
-                self.startrev = rev
-                return True
-
-            if rev > self.startrev:
-                # forward: all descendants
-                if not self.roots:
-                    self.roots.append(self.startrev)
-                for parent in realparents(rev):
-                    if parent in self.roots:
-                        self.roots.append(rev)
-                        return True
-            else:
-                # backwards: all parents
-                if not self.roots:
-                    self.roots.extend(realparents(self.startrev))
-                if rev in self.roots:
-                    self.roots.remove(rev)
-                    self.roots.extend(realparents(rev))
-                    return True
-
-            return False
-
-    # it might be worthwhile to do this in the iterator if the rev range
-    # is descending and the prune args are all within that range
-    for rev in opts.get('prune', ()):
-        rev = repo.changelog.rev(repo.lookup(rev))
-        ff = followfilter()
-        stop = min(revs[0], revs[-1])
-        for x in xrange(rev, stop-1, -1):
-            if ff.match(x) and x in wanted:
-                del wanted[x]
-
-    def iterate():
-        if follow and not files:
-            ff = followfilter(onlyfirst=opts.get('follow_first'))
-            def want(rev):
-                if ff.match(rev) and rev in wanted:
-                    return True
-                return False
-        else:
-            def want(rev):
-                return rev in wanted
-
-        for i, window in increasing_windows(0, len(revs)):
-            yield 'window', revs[0] < revs[-1], revs[-1]
-            nrevs = [rev for rev in revs[i:i+window] if want(rev)]
-            srevs = list(nrevs)
-            srevs.sort()
-            for rev in srevs:
-                fns = fncache.get(rev)
-                if not fns:
-                    def fns_generator():
-                        for f in change(rev)[3]:
-                            if matchfn(f):
-                                yield f
-                    fns = fns_generator()
-                yield 'add', rev, fns
-            for rev in nrevs:
-                yield 'iter', rev, None
-    return iterate(), matchfn
-
 def write_bundle(cg, filename=None, compress=True):
     """Write a bundle file and return its filename.
 
@@ -1352,7 +1158,7 @@
             if opts['all']:
                 cols.append(change)
             if opts['user']:
-                cols.append(ui.shortuser(getchange(r)[1]))
+                cols.append(ui.shortuser(get(r)[1]))
             if opts['files_with_matches']:
                 c = (fn, r)
                 if c in filerevmatches:
@@ -1366,8 +1172,8 @@
 
     fstate = {}
     skip = {}
-    getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
-    changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
+    get = util.cachefunc(lambda r:repo.changectx(r).changeset())
+    changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
     count = 0
     incrementing = False
     follow = opts.get('follow')
@@ -1664,8 +1470,8 @@
     files and full commit message is shown.
     """
 
-    getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
-    changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
+    get = util.cachefunc(lambda r:repo.changectx(r).changeset())
+    changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
 
     if opts['limit']:
         try:
@@ -1725,7 +1531,7 @@
                 continue
 
             if opts['keyword']:
-                changes = getchange(rev)
+                changes = get(rev)
                 miss = 0
                 for k in [kw.lower() for kw in opts['keyword']]:
                     if not (k in changes[1].lower() or
@@ -1738,8 +1544,8 @@
 
             copies = []
             if opts.get('copies') and rev:
-                mf = getchange(rev)[0]
-                for fn in getchange(rev)[3]:
+                mf = get(rev)[0]
+                for fn in get(rev)[3]:
                     rename = getrenamed(fn, rev, mf)
                     if rename:
                         copies.append((fn, rename[0]))