comparison mercurial/commands.py @ 3558:45620faafa28

Pull getchange out of walkchangerevs
author Matt Mackall <mpm@selenic.com>
date Thu, 26 Oct 2006 17:45:03 -0500
parents 68341c06bc61
children cd2216599c99
comparison
equal deleted inserted replaced
3557:68341c06bc61 3558:45620faafa28
48 except IOError, inst: 48 except IOError, inst:
49 raise util.Abort(_("can't read commit message '%s': %s") % 49 raise util.Abort(_("can't read commit message '%s': %s") %
50 (logfile, inst.strerror)) 50 (logfile, inst.strerror))
51 return message 51 return message
52 52
53 def walkchangerevs(ui, repo, pats, opts): 53 def walkchangerevs(ui, repo, pats, change, opts):
54 '''Iterate over files and the revs they changed in. 54 '''Iterate over files and the revs they changed in.
55 55
56 Callers most commonly need to iterate backwards over the history 56 Callers most commonly need to iterate backwards over the history
57 it is interested in. Doing so has awful (quadratic-looking) 57 it is interested in. Doing so has awful (quadratic-looking)
58 performance, so we use iterators in a "windowed" way. 58 performance, so we use iterators in a "windowed" way.
59 59
60 We walk a window of revisions in the desired order. Within the 60 We walk a window of revisions in the desired order. Within the
61 window, we first walk forwards to gather data, then in the desired 61 window, we first walk forwards to gather data, then in the desired
62 order (usually backwards) to display it. 62 order (usually backwards) to display it.
63 63
64 This function returns an (iterator, getchange, matchfn) tuple. The 64 This function returns an (iterator, matchfn) tuple. The iterator
65 getchange function returns the changelog entry for a numeric 65 yields 3-tuples. They will be of one of the following forms:
66 revision. The iterator yields 3-tuples. They will be of one of
67 the following forms:
68 66
69 "window", incrementing, lastrev: stepping through a window, 67 "window", incrementing, lastrev: stepping through a window,
70 positive if walking forwards through revs, last rev in the 68 positive if walking forwards through revs, last rev in the
71 sequence iterated over - use to reset state for the current window 69 sequence iterated over - use to reset state for the current window
72 70
89 yield start, min(windowsize, start-end-1) 87 yield start, min(windowsize, start-end-1)
90 start -= windowsize 88 start -= windowsize
91 if windowsize < sizelimit: 89 if windowsize < sizelimit:
92 windowsize *= 2 90 windowsize *= 2
93 91
94
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) 92 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
96 follow = opts.get('follow') or opts.get('follow_first') 93 follow = opts.get('follow') or opts.get('follow_first')
97 94
98 if repo.changelog.count() == 0: 95 if repo.changelog.count() == 0:
99 return [], False, matchfn 96 return [], matchfn
100 97
101 if follow: 98 if follow:
102 defrange = '%s:0' % repo.changectx().rev() 99 defrange = '%s:0' % repo.changectx().rev()
103 else: 100 else:
104 defrange = 'tip:0' 101 defrange = 'tip:0'
105 revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange]) 102 revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange])
106 wanted = {} 103 wanted = {}
107 slowpath = anypats 104 slowpath = anypats
108 fncache = {} 105 fncache = {}
109
110 chcache = {}
111 def getchange(rev):
112 ch = chcache.get(rev)
113 if ch is None:
114 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
115 return ch
116 106
117 if not slowpath and not files: 107 if not slowpath and not files:
118 # No files, no patterns. Display all revs. 108 # No files, no patterns. Display all revs.
119 wanted = dict(zip(revs, revs)) 109 wanted = dict(zip(revs, revs))
120 copies = [] 110 copies = []
167 157
168 # The slow path checks files modified in every changeset. 158 # The slow path checks files modified in every changeset.
169 def changerevgen(): 159 def changerevgen():
170 for i, window in increasing_windows(repo.changelog.count()-1, -1): 160 for i, window in increasing_windows(repo.changelog.count()-1, -1):
171 for j in xrange(i - window, i + 1): 161 for j in xrange(i - window, i + 1):
172 yield j, getchange(j)[3] 162 yield j, change(j)[3]
173 163
174 for rev, changefiles in changerevgen(): 164 for rev, changefiles in changerevgen():
175 matches = filter(matchfn, changefiles) 165 matches = filter(matchfn, changefiles)
176 if matches: 166 if matches:
177 fncache[rev] = matches 167 fncache[rev] = matches
238 yield 'window', revs[0] < revs[-1], revs[-1] 228 yield 'window', revs[0] < revs[-1], revs[-1]
239 nrevs = [rev for rev in revs[i:i+window] if want(rev)] 229 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
240 srevs = list(nrevs) 230 srevs = list(nrevs)
241 srevs.sort() 231 srevs.sort()
242 for rev in srevs: 232 for rev in srevs:
243 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3]) 233 fns = fncache.get(rev) or filter(matchfn, change(rev)[3])
244 yield 'add', rev, fns 234 yield 'add', rev, fns
245 for rev in nrevs: 235 for rev in nrevs:
246 yield 'iter', rev, None 236 yield 'iter', rev, None
247 return iterate(), getchange, matchfn 237 return iterate(), matchfn
248 238
249 def write_bundle(cg, filename=None, compress=True): 239 def write_bundle(cg, filename=None, compress=True):
250 """Write a bundle file and return its filename. 240 """Write a bundle file and return its filename.
251 241
252 Existing files will not be overwritten. 242 Existing files will not be overwritten.
1489 counts[change] += 1 1479 counts[change] += 1
1490 return counts['+'], counts['-'] 1480 return counts['+'], counts['-']
1491 1481
1492 fstate = {} 1482 fstate = {}
1493 skip = {} 1483 skip = {}
1494 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) 1484 getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
1485 changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
1495 count = 0 1486 count = 0
1496 incrementing = False 1487 incrementing = False
1497 follow = opts.get('follow') 1488 follow = opts.get('follow')
1498 for st, rev, fns in changeiter: 1489 for st, rev, fns in changeiter:
1499 if st == 'window': 1490 if st == 'window':
1822 if self.debugflag: 1813 if self.debugflag:
1823 self.write(*args) 1814 self.write(*args)
1824 def __getattr__(self, key): 1815 def __getattr__(self, key):
1825 return getattr(self.ui, key) 1816 return getattr(self.ui, key)
1826 1817
1827 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) 1818 getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
1819 changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
1828 1820
1829 if opts['branches']: 1821 if opts['branches']:
1830 ui.warn(_("the --branches option is deprecated, " 1822 ui.warn(_("the --branches option is deprecated, "
1831 "please use 'hg branches' instead\n")) 1823 "please use 'hg branches' instead\n"))
1832 1824