##// END OF EJS Templates
Rewrite log command. New version is faster and more featureful....
Bryan O'Sullivan -
r1031:503aaf19 default
parent child Browse files
Show More
@@ -35,7 +35,7 def matchpats(repo, cwd, pats = [], opts
35 35
36 36 def makewalk(repo, pats, opts, head = ''):
37 37 cwd = repo.getcwd()
38 files, matchfn = matchpats(repo, cwd, pats, opts, head)
38 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
39 39 exact = dict(zip(files, files))
40 40 def walk():
41 41 for src, fn in repo.walk(files = files, match = matchfn):
@@ -86,7 +86,7 def revrange(ui, repo, revs, revlog=None
86 86 for rev in xrange(start, end, step):
87 87 yield str(rev)
88 88 else:
89 yield spec
89 yield str(fix(spec, None))
90 90
91 91 def make_filename(repo, r, pat, node=None,
92 92 total=None, seqno=None, revwidth=None):
@@ -193,29 +193,19 def dodiff(fp, ui, repo, node1, node2, f
193 193 tn = None
194 194 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
195 195
196 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None, brinfo=None):
196 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
197 197 """show a single changeset or file revision"""
198 changelog = repo.changelog
199 if filelog:
200 log = filelog
201 filerev = rev
202 node = filenode = filelog.node(filerev)
203 changerev = filelog.linkrev(filenode)
204 changenode = changenode or changelog.node(changerev)
205 else:
206 log = changelog
207 changerev = rev
198 log = repo.changelog
208 199 if changenode is None:
209 changenode = changelog.node(changerev)
210 elif not changerev:
211 rev = changerev = changelog.rev(changenode)
212 node = changenode
200 changenode = log.node(rev)
201 elif not rev:
202 rev = log.rev(changenode)
213 203
214 204 if ui.quiet:
215 ui.write("%d:%s\n" % (rev, hg.short(node)))
205 ui.write("%d:%s\n" % (rev, hg.short(changenode)))
216 206 return
217 207
218 changes = changelog.read(changenode)
208 changes = log.read(changenode)
219 209
220 210 t, tz = changes[2].split(' ')
221 211 # a conversion tool was sticking non-integer offsets into repos
@@ -226,22 +216,20 def show_changeset(ui, repo, rev=0, chan
226 216 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
227 217
228 218 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
229 for p in log.parents(node)
219 for p in log.parents(changenode)
230 220 if ui.debugflag or p != hg.nullid]
231 221 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
232 222 parents = []
233 223
234 224 if ui.verbose:
235 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
225 ui.write("changeset: %d:%s\n" % (rev, hg.hex(changenode)))
236 226 else:
237 ui.write("changeset: %d:%s\n" % (changerev, hg.short(changenode)))
227 ui.write("changeset: %d:%s\n" % (rev, hg.short(changenode)))
238 228
239 229 for tag in repo.nodetags(changenode):
240 230 ui.status("tag: %s\n" % tag)
241 231 for parent in parents:
242 232 ui.write("parent: %d:%s\n" % parent)
243 if filelog:
244 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
245 233
246 234 if brinfo and changenode in brinfo:
247 235 br = brinfo[changenode]
@@ -253,7 +241,7 def show_changeset(ui, repo, rev=0, chan
253 241 ui.status("date: %s\n" % date)
254 242
255 243 if ui.debugflag:
256 files = repo.changes(changelog.parents(changenode)[0], changenode)
244 files = repo.changes(log.parents(changenode)[0], changenode)
257 245 for key, value in zip(["files:", "files+:", "files-:"], files):
258 246 if value:
259 247 ui.note("%-12s %s\n" % (key, " ".join(value)))
@@ -560,7 +548,8 def commit(ui, repo, *pats, **opts):
560 548 if not pats and cwd:
561 549 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
562 550 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
563 fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts)
551 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
552 pats, opts)
564 553 if pats:
565 554 c, a, d, u = repo.changes(files = fns, match = match)
566 555 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
@@ -849,39 +838,90 def locate(ui, repo, *pats, **opts):
849 838 else:
850 839 ui.write(rel, end)
851 840
852 def log(ui, repo, f=None, **opts):
853 """show the revision history of the repository or a single file"""
854 if f:
855 files = relpath(repo, [f])
856 filelog = repo.file(files[0])
857 log = filelog
858 lookup = filelog.lookup
859 else:
860 files = None
861 filelog = None
862 log = repo.changelog
863 lookup = repo.lookup
864 revlist = []
865 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
866 while revs:
867 if len(revs) == 1:
868 revlist.append(revs.pop(0))
869 else:
870 a = revs.pop(0)
871 b = revs.pop(0)
872 off = a > b and -1 or 1
873 revlist.extend(range(a, b + off, off))
841 def log(ui, repo, *pats, **opts):
842 """show revision history of entire repository or files"""
843 # This code most commonly needs to iterate backwards over the
844 # history it is interested in. This has awful (quadratic-looking)
845 # performance, so we use iterators that walk forwards through
846 # windows of revisions, yielding revisions in reverse order, while
847 # walking the windows backwards.
848 files, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
849 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
850 wanted = {}
851 slowpath = anypats
852 window = 300
853 if not slowpath and not files:
854 # No files, no patterns. Display all revs.
855 wanted = dict(zip(revs, revs))
856 if not slowpath:
857 # Only files, no patterns. Check the history of each file.
858 def filerevgen(filelog):
859 for i in xrange(filelog.count() - 1, 0, -window):
860 revs = []
861 for j in xrange(max(0, i - window), i):
862 revs.append(filelog.linkrev(filelog.node(j)))
863 revs.reverse()
864 for rev in revs:
865 yield rev
874 866
875 for i in revlist or range(log.count() - 1, -1, -1):
876 show_changeset(ui, repo, filelog=filelog, rev=i)
867 minrev, maxrev = min(revs), max(revs)
868 for filelog in map(repo.file, files):
869 # A zero count may be a directory or deleted file, so
870 # try to find matching entries on the slow path.
871 if filelog.count() == 0:
872 slowpath = True
873 break
874 for rev in filerevgen(filelog):
875 if rev <= maxrev:
876 if rev < minrev: break
877 wanted[rev] = 1
878 if slowpath:
879 # The slow path checks files modified in every changeset.
880 def mfrevgen():
881 for i in xrange(repo.changelog.count() - 1, 0, -window):
882 for j in xrange(max(0, i - window), i):
883 yield j, repo.changelog.read(repo.lookup(str(j)))[3]
884
885 for rev, mf in mfrevgen():
886 if filter(matchfn, mf):
887 wanted[rev] = 1
888
889 def changerevgen():
890 class dui:
891 # Implement and delegate some ui protocol. Save hunks of
892 # output for later display in the desired order.
893 def __init__(self, ui):
894 self.ui = ui
895 self.hunk = {}
896 def bump(self, rev):
897 self.rev = rev
898 self.hunk[rev] = []
899 def status(self, *args):
900 if not self.quiet: self.write(*args)
901 def write(self, *args):
902 self.hunk[self.rev].append(args)
903 def __getattr__(self, key):
904 return getattr(self.ui, key)
905 for i in xrange(0, len(revs), window):
906 nrevs = [rev for rev in revs[i : min(i + window, len(revs))]
907 if rev in wanted]
908 srevs = list(nrevs)
909 srevs.sort()
910 du = dui(ui)
911 for rev in srevs:
912 du.bump(rev)
913 yield rev, du
914 for rev in nrevs:
915 for args in du.hunk[rev]:
916 ui.write(*args)
917
918 for rev, dui in changerevgen():
919 show_changeset(dui, repo, rev)
877 920 if opts['patch']:
878 if filelog:
879 filenode = filelog.node(i)
880 i = filelog.linkrev(filenode)
881 changenode = repo.changelog.node(i)
921 changenode = repo.changelog.node(rev)
882 922 prev, other = repo.changelog.parents(changenode)
883 dodiff(sys.stdout, ui, repo, prev, changenode, files)
884 ui.write("\n\n")
923 dodiff(dui, dui, repo, prev, changenode, files)
924 du.write("\n\n")
885 925
886 926 def manifest(ui, repo, rev=None):
887 927 """output the latest or given revision of the project manifest"""
@@ -1162,7 +1202,7 def status(ui, repo, *pats, **opts):
1162 1202 '''
1163 1203
1164 1204 cwd = repo.getcwd()
1165 files, matchfn = matchpats(repo, cwd, pats, opts)
1205 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1166 1206 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1167 1207 for n in repo.changes(files=files, match=matchfn)]
1168 1208
@@ -1378,7 +1418,9 table = {
1378 1418 'hg locate [OPTION]... [PATTERN]...'),
1379 1419 "^log|history":
1380 1420 (log,
1381 [('r', 'rev', [], 'revision'),
1421 [('I', 'include', [], 'include path in search'),
1422 ('X', 'exclude', [], 'exclude path from search'),
1423 ('r', 'rev', [], 'revision'),
1382 1424 ('p', 'patch', None, 'show patch')],
1383 1425 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1384 1426 "manifest": (manifest, [], 'hg manifest [REV]'),
@@ -156,11 +156,13 def matcher(repo, cwd, names, inc, exc,
156 156 if exc:
157 157 excmatch = matchfn(map(patkind, exc), '(?:/|$)')
158 158
159 return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and
159 return (roots,
160 lambda fn: (incmatch(fn) and not excmatch(fn) and
160 161 (fn.endswith('/') or
161 162 (not pats and not files) or
162 163 (pats and patmatch(fn)) or
163 (files and filematch(fn))))
164 (files and filematch(fn)))),
165 (inc or exc or (pats and pats != [('glob', '**')])) and True)
164 166
165 167 def system(cmd, errprefix=None):
166 168 """execute a shell command that must succeed"""
General Comments 0
You need to be logged in to leave comments. Login now