##// 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 def makewalk(repo, pats, opts, head = ''):
36 def makewalk(repo, pats, opts, head = ''):
37 cwd = repo.getcwd()
37 cwd = repo.getcwd()
38 files, matchfn = matchpats(repo, cwd, pats, opts, head)
38 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
39 exact = dict(zip(files, files))
39 exact = dict(zip(files, files))
40 def walk():
40 def walk():
41 for src, fn in repo.walk(files = files, match = matchfn):
41 for src, fn in repo.walk(files = files, match = matchfn):
@@ -86,7 +86,7 def revrange(ui, repo, revs, revlog=None
86 for rev in xrange(start, end, step):
86 for rev in xrange(start, end, step):
87 yield str(rev)
87 yield str(rev)
88 else:
88 else:
89 yield spec
89 yield str(fix(spec, None))
90
90
91 def make_filename(repo, r, pat, node=None,
91 def make_filename(repo, r, pat, node=None,
92 total=None, seqno=None, revwidth=None):
92 total=None, seqno=None, revwidth=None):
@@ -193,29 +193,19 def dodiff(fp, ui, repo, node1, node2, f
193 tn = None
193 tn = None
194 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
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 """show a single changeset or file revision"""
197 """show a single changeset or file revision"""
198 changelog = repo.changelog
198 log = 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
208 if changenode is None:
199 if changenode is None:
209 changenode = changelog.node(changerev)
200 changenode = log.node(rev)
210 elif not changerev:
201 elif not rev:
211 rev = changerev = changelog.rev(changenode)
202 rev = log.rev(changenode)
212 node = changenode
213
203
214 if ui.quiet:
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 return
206 return
217
207
218 changes = changelog.read(changenode)
208 changes = log.read(changenode)
219
209
220 t, tz = changes[2].split(' ')
210 t, tz = changes[2].split(' ')
221 # a conversion tool was sticking non-integer offsets into repos
211 # a conversion tool was sticking non-integer offsets into repos
@@ -226,22 +216,20 def show_changeset(ui, repo, rev=0, chan
226 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
216 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
227
217
228 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
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 if ui.debugflag or p != hg.nullid]
220 if ui.debugflag or p != hg.nullid]
231 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
221 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
232 parents = []
222 parents = []
233
223
234 if ui.verbose:
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 else:
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 for tag in repo.nodetags(changenode):
229 for tag in repo.nodetags(changenode):
240 ui.status("tag: %s\n" % tag)
230 ui.status("tag: %s\n" % tag)
241 for parent in parents:
231 for parent in parents:
242 ui.write("parent: %d:%s\n" % parent)
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 if brinfo and changenode in brinfo:
234 if brinfo and changenode in brinfo:
247 br = brinfo[changenode]
235 br = brinfo[changenode]
@@ -253,7 +241,7 def show_changeset(ui, repo, rev=0, chan
253 ui.status("date: %s\n" % date)
241 ui.status("date: %s\n" % date)
254
242
255 if ui.debugflag:
243 if ui.debugflag:
256 files = repo.changes(changelog.parents(changenode)[0], changenode)
244 files = repo.changes(log.parents(changenode)[0], changenode)
257 for key, value in zip(["files:", "files+:", "files-:"], files):
245 for key, value in zip(["files:", "files+:", "files-:"], files):
258 if value:
246 if value:
259 ui.note("%-12s %s\n" % (key, " ".join(value)))
247 ui.note("%-12s %s\n" % (key, " ".join(value)))
@@ -560,7 +548,8 def commit(ui, repo, *pats, **opts):
560 if not pats and cwd:
548 if not pats and cwd:
561 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
549 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
562 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
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 if pats:
553 if pats:
565 c, a, d, u = repo.changes(files = fns, match = match)
554 c, a, d, u = repo.changes(files = fns, match = match)
566 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
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 else:
838 else:
850 ui.write(rel, end)
839 ui.write(rel, end)
851
840
852 def log(ui, repo, f=None, **opts):
841 def log(ui, repo, *pats, **opts):
853 """show the revision history of the repository or a single file"""
842 """show revision history of entire repository or files"""
854 if f:
843 # This code most commonly needs to iterate backwards over the
855 files = relpath(repo, [f])
844 # history it is interested in. This has awful (quadratic-looking)
856 filelog = repo.file(files[0])
845 # performance, so we use iterators that walk forwards through
857 log = filelog
846 # windows of revisions, yielding revisions in reverse order, while
858 lookup = filelog.lookup
847 # walking the windows backwards.
859 else:
848 files, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
860 files = None
849 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
861 filelog = None
850 wanted = {}
862 log = repo.changelog
851 slowpath = anypats
863 lookup = repo.lookup
852 window = 300
864 revlist = []
853 if not slowpath and not files:
865 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
854 # No files, no patterns. Display all revs.
866 while revs:
855 wanted = dict(zip(revs, revs))
867 if len(revs) == 1:
856 if not slowpath:
868 revlist.append(revs.pop(0))
857 # Only files, no patterns. Check the history of each file.
869 else:
858 def filerevgen(filelog):
870 a = revs.pop(0)
859 for i in xrange(filelog.count() - 1, 0, -window):
871 b = revs.pop(0)
860 revs = []
872 off = a > b and -1 or 1
861 for j in xrange(max(0, i - window), i):
873 revlist.extend(range(a, b + off, off))
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):
867 minrev, maxrev = min(revs), max(revs)
876 show_changeset(ui, repo, filelog=filelog, rev=i)
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 if opts['patch']:
920 if opts['patch']:
878 if filelog:
921 changenode = repo.changelog.node(rev)
879 filenode = filelog.node(i)
880 i = filelog.linkrev(filenode)
881 changenode = repo.changelog.node(i)
882 prev, other = repo.changelog.parents(changenode)
922 prev, other = repo.changelog.parents(changenode)
883 dodiff(sys.stdout, ui, repo, prev, changenode, files)
923 dodiff(dui, dui, repo, prev, changenode, files)
884 ui.write("\n\n")
924 du.write("\n\n")
885
925
886 def manifest(ui, repo, rev=None):
926 def manifest(ui, repo, rev=None):
887 """output the latest or given revision of the project manifest"""
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 cwd = repo.getcwd()
1204 cwd = repo.getcwd()
1165 files, matchfn = matchpats(repo, cwd, pats, opts)
1205 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1166 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1206 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1167 for n in repo.changes(files=files, match=matchfn)]
1207 for n in repo.changes(files=files, match=matchfn)]
1168
1208
@@ -1378,7 +1418,9 table = {
1378 'hg locate [OPTION]... [PATTERN]...'),
1418 'hg locate [OPTION]... [PATTERN]...'),
1379 "^log|history":
1419 "^log|history":
1380 (log,
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 ('p', 'patch', None, 'show patch')],
1424 ('p', 'patch', None, 'show patch')],
1383 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1425 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1384 "manifest": (manifest, [], 'hg manifest [REV]'),
1426 "manifest": (manifest, [], 'hg manifest [REV]'),
@@ -156,11 +156,13 def matcher(repo, cwd, names, inc, exc,
156 if exc:
156 if exc:
157 excmatch = matchfn(map(patkind, exc), '(?:/|$)')
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 (fn.endswith('/') or
161 (fn.endswith('/') or
161 (not pats and not files) or
162 (not pats and not files) or
162 (pats and patmatch(fn)) or
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 def system(cmd, errprefix=None):
167 def system(cmd, errprefix=None):
166 """execute a shell command that must succeed"""
168 """execute a shell command that must succeed"""
General Comments 0
You need to be logged in to leave comments. Login now