10 import tempfile, urllib, bz2 |
10 import tempfile, urllib, bz2 |
11 from mercurial.node import * |
11 from mercurial.node import * |
12 from mercurial.i18n import gettext as _ |
12 from mercurial.i18n import gettext as _ |
13 from mercurial import mdiff, ui, hg, util, archival, streamclone, patch |
13 from mercurial import mdiff, ui, hg, util, archival, streamclone, patch |
14 from mercurial import revlog, templater |
14 from mercurial import revlog, templater |
15 from common import get_mtime, staticfile, style_map |
15 from common import get_mtime, staticfile, style_map, paritygen |
16 |
16 |
17 def _up(p): |
17 def _up(p): |
18 if p[0] != "/": |
18 if p[0] != "/": |
19 p = "/" + p |
19 p = "/" + p |
20 if p[-1] == "/": |
20 if p[-1] == "/": |
145 if t and t[-1] != os.sep: |
145 if t and t[-1] != os.sep: |
146 t += os.sep |
146 t += os.sep |
147 l += [x for x in files if x.startswith(t)] |
147 l += [x for x in files if x.startswith(t)] |
148 return l |
148 return l |
149 |
149 |
150 parity = [0] |
150 parity = paritygen(self.stripecount) |
151 def diffblock(diff, f, fn): |
151 def diffblock(diff, f, fn): |
152 yield self.t("diffblock", |
152 yield self.t("diffblock", |
153 lines=prettyprintlines(diff), |
153 lines=prettyprintlines(diff), |
154 parity=parity[0], |
154 parity=parity.next(), |
155 file=f, |
155 file=f, |
156 filenode=hex(fn or nullid)) |
156 filenode=hex(fn or nullid)) |
157 parity[0] = 1 - parity[0] |
|
158 |
157 |
159 def prettyprintlines(diff): |
158 def prettyprintlines(diff): |
160 for l in diff.splitlines(1): |
159 for l in diff.splitlines(1): |
161 if l.startswith('+'): |
160 if l.startswith('+'): |
162 yield self.t("difflineplus", line=l) |
161 yield self.t("difflineplus", line=l) |
195 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
194 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
196 opts=diffopts), f, tn) |
195 opts=diffopts), f, tn) |
197 |
196 |
198 def changelog(self, ctx, shortlog=False): |
197 def changelog(self, ctx, shortlog=False): |
199 def changelist(**map): |
198 def changelist(**map): |
200 parity = (start - end) & 1 |
|
201 cl = self.repo.changelog |
199 cl = self.repo.changelog |
202 l = [] # build a list in forward order for efficiency |
200 l = [] # build a list in forward order for efficiency |
203 for i in xrange(start, end): |
201 for i in xrange(start, end): |
204 ctx = self.repo.changectx(i) |
202 ctx = self.repo.changectx(i) |
205 n = ctx.node() |
203 n = ctx.node() |
206 |
204 |
207 l.insert(0, {"parity": parity, |
205 l.insert(0, {"parity": parity.next(), |
208 "author": ctx.user(), |
206 "author": ctx.user(), |
209 "parent": self.siblings(ctx.parents(), i - 1), |
207 "parent": self.siblings(ctx.parents(), i - 1), |
210 "child": self.siblings(ctx.children(), i + 1), |
208 "child": self.siblings(ctx.children(), i + 1), |
211 "changelogtag": self.showtag("changelogtag",n), |
209 "changelogtag": self.showtag("changelogtag",n), |
212 "desc": ctx.description(), |
210 "desc": ctx.description(), |
213 "date": ctx.date(), |
211 "date": ctx.date(), |
214 "files": self.listfilediffs(ctx.files(), n), |
212 "files": self.listfilediffs(ctx.files(), n), |
215 "rev": i, |
213 "rev": i, |
216 "node": hex(n)}) |
214 "node": hex(n)}) |
217 parity = 1 - parity |
|
218 |
215 |
219 for e in l: |
216 for e in l: |
220 yield e |
217 yield e |
221 |
218 |
222 maxchanges = shortlog and self.maxshortchanges or self.maxchanges |
219 maxchanges = shortlog and self.maxshortchanges or self.maxchanges |
224 count = cl.count() |
221 count = cl.count() |
225 pos = ctx.rev() |
222 pos = ctx.rev() |
226 start = max(0, pos - maxchanges + 1) |
223 start = max(0, pos - maxchanges + 1) |
227 end = min(count, start + maxchanges) |
224 end = min(count, start + maxchanges) |
228 pos = end - 1 |
225 pos = end - 1 |
|
226 parity = paritygen(self.stripecount, offset=start-end) |
229 |
227 |
230 changenav = revnavgen(pos, maxchanges, count, self.repo.changectx) |
228 changenav = revnavgen(pos, maxchanges, count, self.repo.changectx) |
231 |
229 |
232 yield self.t(shortlog and 'shortlog' or 'changelog', |
230 yield self.t(shortlog and 'shortlog' or 'changelog', |
233 changenav=changenav, |
231 changenav=changenav, |
265 |
263 |
266 count += 1 |
264 count += 1 |
267 n = ctx.node() |
265 n = ctx.node() |
268 |
266 |
269 yield self.t('searchentry', |
267 yield self.t('searchentry', |
270 parity=self.stripes(count), |
268 parity=parity.next(), |
271 author=ctx.user(), |
269 author=ctx.user(), |
272 parent=self.siblings(ctx.parents()), |
270 parent=self.siblings(ctx.parents()), |
273 child=self.siblings(ctx.children()), |
271 child=self.siblings(ctx.children()), |
274 changelogtag=self.showtag("changelogtag",n), |
272 changelogtag=self.showtag("changelogtag",n), |
275 desc=ctx.description(), |
273 desc=ctx.description(), |
292 n = ctx.node() |
291 n = ctx.node() |
293 parents = ctx.parents() |
292 parents = ctx.parents() |
294 p1 = parents[0].node() |
293 p1 = parents[0].node() |
295 |
294 |
296 files = [] |
295 files = [] |
297 parity = 0 |
296 parity = paritygen(self.stripecount) |
298 for f in ctx.files(): |
297 for f in ctx.files(): |
299 files.append(self.t("filenodelink", |
298 files.append(self.t("filenodelink", |
300 node=hex(n), file=f, |
299 node=hex(n), file=f, |
301 parity=parity)) |
300 parity=parity.next())) |
302 parity = 1 - parity |
|
303 |
301 |
304 def diff(**map): |
302 def diff(**map): |
305 yield self.diff(p1, n, None) |
303 yield self.diff(p1, n, None) |
306 |
304 |
307 yield self.t('changeset', |
305 yield self.t('changeset', |
324 pagelen = self.maxshortchanges |
322 pagelen = self.maxshortchanges |
325 pos = fctx.filerev() |
323 pos = fctx.filerev() |
326 start = max(0, pos - pagelen + 1) |
324 start = max(0, pos - pagelen + 1) |
327 end = min(count, start + pagelen) |
325 end = min(count, start + pagelen) |
328 pos = end - 1 |
326 pos = end - 1 |
|
327 parity = paritygen(self.stripecount, offset=start-end) |
329 |
328 |
330 def entries(**map): |
329 def entries(**map): |
331 l = [] |
330 l = [] |
332 parity = (count - 1) & 1 |
|
333 |
331 |
334 for i in xrange(start, end): |
332 for i in xrange(start, end): |
335 ctx = fctx.filectx(i) |
333 ctx = fctx.filectx(i) |
336 n = fl.node(i) |
334 n = fl.node(i) |
337 |
335 |
338 l.insert(0, {"parity": parity, |
336 l.insert(0, {"parity": parity.next(), |
339 "filerev": i, |
337 "filerev": i, |
340 "file": f, |
338 "file": f, |
341 "node": hex(ctx.node()), |
339 "node": hex(ctx.node()), |
342 "author": ctx.user(), |
340 "author": ctx.user(), |
343 "date": ctx.date(), |
341 "date": ctx.date(), |
344 "rename": self.renamelink(fl, n), |
342 "rename": self.renamelink(fl, n), |
345 "parent": self.siblings(fctx.parents()), |
343 "parent": self.siblings(fctx.parents()), |
346 "child": self.siblings(fctx.children()), |
344 "child": self.siblings(fctx.children()), |
347 "desc": ctx.description()}) |
345 "desc": ctx.description()}) |
348 parity = 1 - parity |
|
349 |
346 |
350 for e in l: |
347 for e in l: |
351 yield e |
348 yield e |
352 |
349 |
353 nodefunc = lambda x: fctx.filectx(fileid=x) |
350 nodefunc = lambda x: fctx.filectx(fileid=x) |
392 |
390 |
393 def fileannotate(self, fctx): |
391 def fileannotate(self, fctx): |
394 f = fctx.path() |
392 f = fctx.path() |
395 n = fctx.filenode() |
393 n = fctx.filenode() |
396 fl = fctx.filelog() |
394 fl = fctx.filelog() |
|
395 parity = paritygen(self.stripecount) |
397 |
396 |
398 def annotate(**map): |
397 def annotate(**map): |
399 parity = 0 |
|
400 last = None |
398 last = None |
401 for f, l in fctx.annotate(follow=True): |
399 for f, l in fctx.annotate(follow=True): |
402 fnode = f.filenode() |
400 fnode = f.filenode() |
403 name = self.repo.ui.shortuser(f.user()) |
401 name = self.repo.ui.shortuser(f.user()) |
404 |
402 |
405 if last != fnode: |
403 if last != fnode: |
406 parity = 1 - parity |
|
407 last = fnode |
404 last = fnode |
408 |
405 |
409 yield {"parity": parity, |
406 yield {"parity": parity.next(), |
410 "node": hex(f.node()), |
407 "node": hex(f.node()), |
411 "rev": f.rev(), |
408 "rev": f.rev(), |
412 "author": name, |
409 "author": name, |
413 "file": f.path(), |
410 "file": f.path(), |
414 "line": l} |
411 "line": l} |
448 else: |
446 else: |
449 short = os.path.basename(remain) |
447 short = os.path.basename(remain) |
450 files[short] = (f, n) |
448 files[short] = (f, n) |
451 |
449 |
452 def filelist(**map): |
450 def filelist(**map): |
453 parity = 0 |
|
454 fl = files.keys() |
451 fl = files.keys() |
455 fl.sort() |
452 fl.sort() |
456 for f in fl: |
453 for f in fl: |
457 full, fnode = files[f] |
454 full, fnode = files[f] |
458 if not fnode: |
455 if not fnode: |
459 continue |
456 continue |
460 |
457 |
461 yield {"file": full, |
458 yield {"file": full, |
462 "parity": self.stripes(parity), |
459 "parity": parity.next(), |
463 "basename": f, |
460 "basename": f, |
464 "size": ctx.filectx(full).size(), |
461 "size": ctx.filectx(full).size(), |
465 "permissions": mf.execf(full)} |
462 "permissions": mf.execf(full)} |
466 parity += 1 |
|
467 |
463 |
468 def dirlist(**map): |
464 def dirlist(**map): |
469 parity = 0 |
|
470 fl = files.keys() |
465 fl = files.keys() |
471 fl.sort() |
466 fl.sort() |
472 for f in fl: |
467 for f in fl: |
473 full, fnode = files[f] |
468 full, fnode = files[f] |
474 if fnode: |
469 if fnode: |
475 continue |
470 continue |
476 |
471 |
477 yield {"parity": self.stripes(parity), |
472 yield {"parity": parity.next(), |
478 "path": os.path.join(abspath, f), |
473 "path": os.path.join(abspath, f), |
479 "basename": f[:-1]} |
474 "basename": f[:-1]} |
480 parity += 1 |
|
481 |
475 |
482 yield self.t("manifest", |
476 yield self.t("manifest", |
483 rev=ctx.rev(), |
477 rev=ctx.rev(), |
484 node=hex(node), |
478 node=hex(node), |
485 path=abspath, |
479 path=abspath, |
486 up=_up(abspath), |
480 up=_up(abspath), |
487 upparity=self.stripes(0), |
481 upparity=parity.next(), |
488 fentries=filelist, |
482 fentries=filelist, |
489 dentries=dirlist, |
483 dentries=dirlist, |
490 archives=self.archivelist(hex(node))) |
484 archives=self.archivelist(hex(node))) |
491 |
485 |
492 def tags(self): |
486 def tags(self): |
493 i = self.repo.tagslist() |
487 i = self.repo.tagslist() |
494 i.reverse() |
488 i.reverse() |
|
489 parity = paritygen(self.stripecount) |
495 |
490 |
496 def entries(notip=False, **map): |
491 def entries(notip=False, **map): |
497 parity = 0 |
|
498 for k, n in i: |
492 for k, n in i: |
499 if notip and k == "tip": |
493 if notip and k == "tip": |
500 continue |
494 continue |
501 yield {"parity": self.stripes(parity), |
495 yield {"parity": parity.next(), |
502 "tag": k, |
496 "tag": k, |
503 "date": self.repo.changectx(n).date(), |
497 "date": self.repo.changectx(n).date(), |
504 "node": hex(n)} |
498 "node": hex(n)} |
505 parity += 1 |
|
506 |
499 |
507 yield self.t("tags", |
500 yield self.t("tags", |
508 node=hex(self.repo.changelog.tip()), |
501 node=hex(self.repo.changelog.tip()), |
509 entries=lambda **x: entries(False, **x), |
502 entries=lambda **x: entries(False, **x), |
510 entriesnotip=lambda **x: entries(True, **x)) |
503 entriesnotip=lambda **x: entries(True, **x)) |
512 def summary(self): |
505 def summary(self): |
513 i = self.repo.tagslist() |
506 i = self.repo.tagslist() |
514 i.reverse() |
507 i.reverse() |
515 |
508 |
516 def tagentries(**map): |
509 def tagentries(**map): |
517 parity = 0 |
510 parity = paritygen(self.stripecount) |
518 count = 0 |
511 count = 0 |
519 for k, n in i: |
512 for k, n in i: |
520 if k == "tip": # skip tip |
513 if k == "tip": # skip tip |
521 continue; |
514 continue; |
522 |
515 |
523 count += 1 |
516 count += 1 |
524 if count > 10: # limit to 10 tags |
517 if count > 10: # limit to 10 tags |
525 break; |
518 break; |
526 |
519 |
527 yield self.t("tagentry", |
520 yield self.t("tagentry", |
528 parity=self.stripes(parity), |
521 parity=parity.next(), |
529 tag=k, |
522 tag=k, |
530 node=hex(n), |
523 node=hex(n), |
531 date=self.repo.changectx(n).date()) |
524 date=self.repo.changectx(n).date()) |
532 parity += 1 |
|
533 |
525 |
534 |
526 |
535 def branches(**map): |
527 def branches(**map): |
536 parity = 0 |
528 parity = paritygen(self.stripecount) |
537 |
529 |
538 b = self.repo.branchtags() |
530 b = self.repo.branchtags() |
539 l = [(-self.repo.changelog.rev(n), n, t) for t, n in b.items()] |
531 l = [(-self.repo.changelog.rev(n), n, t) for t, n in b.items()] |
540 l.sort() |
532 l.sort() |
541 |
533 |
542 for r,n,t in l: |
534 for r,n,t in l: |
543 ctx = self.repo.changectx(n) |
535 ctx = self.repo.changectx(n) |
544 |
536 |
545 yield {'parity': self.stripes(parity), |
537 yield {'parity': parity.next(), |
546 'branch': t, |
538 'branch': t, |
547 'node': hex(n), |
539 'node': hex(n), |
548 'date': ctx.date()} |
540 'date': ctx.date()} |
549 parity += 1 |
|
550 |
541 |
551 def changelist(**map): |
542 def changelist(**map): |
552 parity = 0 |
543 parity = paritygen(self.stripecount, offset=start-end) |
553 l = [] # build a list in forward order for efficiency |
544 l = [] # build a list in forward order for efficiency |
554 for i in xrange(start, end): |
545 for i in xrange(start, end): |
555 ctx = self.repo.changectx(i) |
546 ctx = self.repo.changectx(i) |
556 hn = hex(ctx.node()) |
547 hn = hex(ctx.node()) |
557 |
548 |
558 l.insert(0, self.t( |
549 l.insert(0, self.t( |
559 'shortlogentry', |
550 'shortlogentry', |
560 parity=parity, |
551 parity=parity.next(), |
561 author=ctx.user(), |
552 author=ctx.user(), |
562 desc=ctx.description(), |
553 desc=ctx.description(), |
563 date=ctx.date(), |
554 date=ctx.date(), |
564 rev=i, |
555 rev=i, |
565 node=hn)) |
556 node=hn)) |
566 parity = 1 - parity |
|
567 |
557 |
568 yield l |
558 yield l |
569 |
559 |
570 cl = self.repo.changelog |
560 cl = self.repo.changelog |
571 count = cl.count() |
561 count = cl.count() |
843 fctx = ctx.filectx(path) |
833 fctx = ctx.filectx(path) |
844 except hg.RepoError: |
834 except hg.RepoError: |
845 fctx = self.repo.filectx(path, fileid=changeid) |
835 fctx = self.repo.filectx(path, fileid=changeid) |
846 |
836 |
847 return fctx |
837 return fctx |
848 |
|
849 def stripes(self, parity): |
|
850 "make horizontal stripes for easier reading" |
|
851 if self.stripecount: |
|
852 return (1 + parity / self.stripecount) & 1 |
|
853 else: |
|
854 return 0 |
|
855 |
838 |
856 def do_log(self, req): |
839 def do_log(self, req): |
857 if req.form.has_key('file') and req.form['file'][0]: |
840 if req.form.has_key('file') and req.form['file'][0]: |
858 self.do_filelog(req) |
841 self.do_filelog(req) |
859 else: |
842 else: |