--- 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]))