Mercurial > public > mercurial-scm > hg
comparison mercurial/commands.py @ 3568:23f7d9621783
Merge with upstream
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 27 Oct 2006 23:09:46 +0200 |
parents | eda9e7c9300d 730ca93ed788 |
children | 736a78469a85 |
comparison
equal
deleted
inserted
replaced
3567:3bab1fc0ab75 | 3568:23f7d9621783 |
---|---|
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 = map(int, 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 | 106 |
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 | |
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.fromkeys(revs) |
120 copies = [] | 110 copies = [] |
121 if not slowpath: | 111 if not slowpath: |
122 # Only files, no patterns. Check the history of each file. | 112 # Only files, no patterns. Check the history of each file. |
123 def filerevgen(filelog, node): | 113 def filerevgen(filelog, node): |
124 cl_count = repo.changelog.count() | 114 cl_count = repo.changelog.count() |
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 |
218 for rev in opts.get('prune', ()): | 208 for rev in opts.get('prune', ()): |
219 rev = repo.changelog.rev(repo.lookup(rev)) | 209 rev = repo.changelog.rev(repo.lookup(rev)) |
220 ff = followfilter() | 210 ff = followfilter() |
221 stop = min(revs[0], revs[-1]) | 211 stop = min(revs[0], revs[-1]) |
222 for x in xrange(rev, stop-1, -1): | 212 for x in xrange(rev, stop-1, -1): |
223 if ff.match(x) and wanted.has_key(x): | 213 if ff.match(x) and x in wanted: |
224 del wanted[x] | 214 del wanted[x] |
225 | 215 |
226 def iterate(): | 216 def iterate(): |
227 if follow and not files: | 217 if follow and not files: |
228 ff = followfilter(onlyfirst=opts.get('follow_first')) | 218 ff = followfilter(onlyfirst=opts.get('follow_first')) |
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. |
295 finally: | 285 finally: |
296 if fh is not None: | 286 if fh is not None: |
297 fh.close() | 287 fh.close() |
298 if cleanup is not None: | 288 if cleanup is not None: |
299 os.unlink(cleanup) | 289 os.unlink(cleanup) |
300 | |
301 def trimuser(ui, name, rev, revcache): | |
302 """trim the name of the user who committed a change""" | |
303 user = revcache.get(rev) | |
304 if user is None: | |
305 user = revcache[rev] = ui.shortuser(name) | |
306 return user | |
307 | 290 |
308 class changeset_printer(object): | 291 class changeset_printer(object): |
309 '''show changeset information when templating not requested.''' | 292 '''show changeset information when templating not requested.''' |
310 | 293 |
311 def __init__(self, ui, repo): | 294 def __init__(self, ui, repo): |
1381 With the --switch-parent option, the diff will be against the second | 1364 With the --switch-parent option, the diff will be against the second |
1382 parent. It can be useful to review a merge. | 1365 parent. It can be useful to review a merge. |
1383 """ | 1366 """ |
1384 if not changesets: | 1367 if not changesets: |
1385 raise util.Abort(_("export requires at least one changeset")) | 1368 raise util.Abort(_("export requires at least one changeset")) |
1386 revs = list(cmdutil.revrange(ui, repo, changesets)) | 1369 revs = cmdutil.revrange(ui, repo, changesets) |
1387 if len(revs) > 1: | 1370 if len(revs) > 1: |
1388 ui.note(_('exporting patches:\n')) | 1371 ui.note(_('exporting patches:\n')) |
1389 else: | 1372 else: |
1390 ui.note(_('exporting patch:\n')) | 1373 ui.note(_('exporting patch:\n')) |
1391 patch.export(repo, map(repo.lookup, revs), template=opts['output'], | 1374 patch.export(repo, map(repo.lookup, revs), template=opts['output'], |
1469 yield ('-', a[i]) | 1452 yield ('-', a[i]) |
1470 for i in xrange(blo, bhi): | 1453 for i in xrange(blo, bhi): |
1471 yield ('+', b[i]) | 1454 yield ('+', b[i]) |
1472 | 1455 |
1473 prev = {} | 1456 prev = {} |
1474 ucache = {} | |
1475 def display(fn, rev, states, prevstates): | 1457 def display(fn, rev, states, prevstates): |
1476 counts = {'-': 0, '+': 0} | 1458 counts = {'-': 0, '+': 0} |
1477 filerevmatches = {} | 1459 filerevmatches = {} |
1478 if incrementing or not opts['all']: | 1460 if incrementing or not opts['all']: |
1479 a, b = prevstates, states | 1461 a, b, r = prevstates, states, rev |
1480 else: | 1462 else: |
1481 a, b = states, prevstates | 1463 a, b, r = states, prevstates, prev.get(fn, -1) |
1482 for change, l in difflinestates(a, b): | 1464 for change, l in difflinestates(a, b): |
1483 if incrementing or not opts['all']: | |
1484 r = rev | |
1485 else: | |
1486 r = prev[fn] | |
1487 cols = [fn, str(r)] | 1465 cols = [fn, str(r)] |
1488 if opts['line_number']: | 1466 if opts['line_number']: |
1489 cols.append(str(l.linenum)) | 1467 cols.append(str(l.linenum)) |
1490 if opts['all']: | 1468 if opts['all']: |
1491 cols.append(change) | 1469 cols.append(change) |
1492 if opts['user']: | 1470 if opts['user']: |
1493 cols.append(trimuser(ui, getchange(r)[1], rev, | 1471 cols.append(ui.shortuser(getchange(r)[1])) |
1494 ucache)) | |
1495 if opts['files_with_matches']: | 1472 if opts['files_with_matches']: |
1496 c = (fn, rev) | 1473 c = (fn, r) |
1497 if c in filerevmatches: | 1474 if c in filerevmatches: |
1498 continue | 1475 continue |
1499 filerevmatches[c] = 1 | 1476 filerevmatches[c] = 1 |
1500 else: | 1477 else: |
1501 cols.append(l.line) | 1478 cols.append(l.line) |
1503 counts[change] += 1 | 1480 counts[change] += 1 |
1504 return counts['+'], counts['-'] | 1481 return counts['+'], counts['-'] |
1505 | 1482 |
1506 fstate = {} | 1483 fstate = {} |
1507 skip = {} | 1484 skip = {} |
1508 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) | 1485 getchange = util.cachefunc(lambda r:repo.changectx(r).changeset()) |
1486 changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts) | |
1509 count = 0 | 1487 count = 0 |
1510 incrementing = False | 1488 incrementing = False |
1511 follow = opts.get('follow') | 1489 follow = opts.get('follow') |
1512 for st, rev, fns in changeiter: | 1490 for st, rev, fns in changeiter: |
1513 if st == 'window': | 1491 if st == 'window': |
1514 incrementing = rev | 1492 incrementing = rev |
1515 matches.clear() | 1493 matches.clear() |
1516 elif st == 'add': | 1494 elif st == 'add': |
1517 change = repo.changelog.read(repo.lookup(str(rev))) | 1495 mf = repo.changectx(rev).manifest() |
1518 mf = repo.manifest.read(change[0]) | |
1519 matches[rev] = {} | 1496 matches[rev] = {} |
1520 for fn in fns: | 1497 for fn in fns: |
1521 if fn in skip: | 1498 if fn in skip: |
1522 continue | 1499 continue |
1523 fstate.setdefault(fn, {}) | 1500 fstate.setdefault(fn, {}) |
1836 if self.debugflag: | 1813 if self.debugflag: |
1837 self.write(*args) | 1814 self.write(*args) |
1838 def __getattr__(self, key): | 1815 def __getattr__(self, key): |
1839 return getattr(self.ui, key) | 1816 return getattr(self.ui, key) |
1840 | 1817 |
1841 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) | |
1842 | 1820 |
1843 if opts['branches']: | 1821 if opts['branches']: |
1844 ui.warn(_("the --branches option is deprecated, " | 1822 ui.warn(_("the --branches option is deprecated, " |
1845 "please use 'hg branches' instead\n")) | 1823 "please use 'hg branches' instead\n")) |
1846 | 1824 |
1853 else: | 1831 else: |
1854 limit = sys.maxint | 1832 limit = sys.maxint |
1855 count = 0 | 1833 count = 0 |
1856 | 1834 |
1857 if opts['copies'] and opts['rev']: | 1835 if opts['copies'] and opts['rev']: |
1858 endrev = max([int(i) | 1836 endrev = max(cmdutil.revrange(ui, repo, opts['rev'])) + 1 |
1859 for i in cmdutil.revrange(ui, repo, opts['rev'])]) + 1 | |
1860 else: | 1837 else: |
1861 endrev = repo.changelog.count() | 1838 endrev = repo.changelog.count() |
1862 rcache = {} | 1839 rcache = {} |
1863 ncache = {} | 1840 ncache = {} |
1864 dcache = [] | 1841 dcache = [] |