405 to = c1.filectx(f).data() |
356 to = c1.filectx(f).data() |
406 tn = None |
357 tn = None |
407 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f, |
358 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f, |
408 opts=diffopts), f, tn) |
359 opts=diffopts), f, tn) |
409 |
360 |
410 def changelog(self, tmpl, ctx, shortlog=False): |
|
411 def changelist(limit=0,**map): |
|
412 cl = self.repo.changelog |
|
413 l = [] # build a list in forward order for efficiency |
|
414 for i in xrange(start, end): |
|
415 ctx = self.repo.changectx(i) |
|
416 n = ctx.node() |
|
417 showtags = webutil.showtag(self.repo, tmpl, 'changelogtag', n) |
|
418 |
|
419 l.insert(0, {"parity": parity.next(), |
|
420 "author": ctx.user(), |
|
421 "parent": webutil.siblings(ctx.parents(), i - 1), |
|
422 "child": webutil.siblings(ctx.children(), i + 1), |
|
423 "changelogtag": showtags, |
|
424 "desc": ctx.description(), |
|
425 "date": ctx.date(), |
|
426 "files": self.listfilediffs(tmpl, ctx.files(), n), |
|
427 "rev": i, |
|
428 "node": hex(n), |
|
429 "tags": webutil.nodetagsdict(self.repo, n), |
|
430 "inbranch": webutil.nodeinbranch(self.repo, ctx), |
|
431 "branches": webutil.nodebranchdict(self.repo, ctx) |
|
432 }) |
|
433 |
|
434 if limit > 0: |
|
435 l = l[:limit] |
|
436 |
|
437 for e in l: |
|
438 yield e |
|
439 |
|
440 maxchanges = shortlog and self.maxshortchanges or self.maxchanges |
|
441 cl = self.repo.changelog |
|
442 count = cl.count() |
|
443 pos = ctx.rev() |
|
444 start = max(0, pos - maxchanges + 1) |
|
445 end = min(count, start + maxchanges) |
|
446 pos = end - 1 |
|
447 parity = paritygen(self.stripecount, offset=start-end) |
|
448 |
|
449 changenav = revnavgen(pos, maxchanges, count, self.repo.changectx) |
|
450 |
|
451 return tmpl(shortlog and 'shortlog' or 'changelog', |
|
452 changenav=changenav, |
|
453 node=hex(cl.tip()), |
|
454 rev=pos, changesets=count, |
|
455 entries=lambda **x: changelist(limit=0,**x), |
|
456 latestentry=lambda **x: changelist(limit=1,**x), |
|
457 archives=self.archivelist("tip")) |
|
458 |
|
459 def search(self, tmpl, query): |
|
460 |
|
461 def changelist(**map): |
|
462 cl = self.repo.changelog |
|
463 count = 0 |
|
464 qw = query.lower().split() |
|
465 |
|
466 def revgen(): |
|
467 for i in xrange(cl.count() - 1, 0, -100): |
|
468 l = [] |
|
469 for j in xrange(max(0, i - 100), i + 1): |
|
470 ctx = self.repo.changectx(j) |
|
471 l.append(ctx) |
|
472 l.reverse() |
|
473 for e in l: |
|
474 yield e |
|
475 |
|
476 for ctx in revgen(): |
|
477 miss = 0 |
|
478 for q in qw: |
|
479 if not (q in ctx.user().lower() or |
|
480 q in ctx.description().lower() or |
|
481 q in " ".join(ctx.files()).lower()): |
|
482 miss = 1 |
|
483 break |
|
484 if miss: |
|
485 continue |
|
486 |
|
487 count += 1 |
|
488 n = ctx.node() |
|
489 showtags = webutil.showtag(self.repo, tmpl, 'changelogtag', n) |
|
490 |
|
491 yield tmpl('searchentry', |
|
492 parity=parity.next(), |
|
493 author=ctx.user(), |
|
494 parent=webutil.siblings(ctx.parents()), |
|
495 child=webutil.siblings(ctx.children()), |
|
496 changelogtag=showtags, |
|
497 desc=ctx.description(), |
|
498 date=ctx.date(), |
|
499 files=self.listfilediffs(tmpl, ctx.files(), n), |
|
500 rev=ctx.rev(), |
|
501 node=hex(n), |
|
502 tags=webutil.nodetagsdict(self.repo, n), |
|
503 inbranch=webutil.nodeinbranch(self.repo, ctx), |
|
504 branches=webutil.nodebranchdict(self.repo, ctx)) |
|
505 |
|
506 if count >= self.maxchanges: |
|
507 break |
|
508 |
|
509 cl = self.repo.changelog |
|
510 parity = paritygen(self.stripecount) |
|
511 |
|
512 return tmpl('search', |
|
513 query=query, |
|
514 node=hex(cl.tip()), |
|
515 entries=changelist, |
|
516 archives=self.archivelist("tip")) |
|
517 |
|
518 def changeset(self, tmpl, ctx): |
|
519 n = ctx.node() |
|
520 showtags = webutil.showtag(self.repo, tmpl, 'changesettag', n) |
|
521 parents = ctx.parents() |
|
522 p1 = parents[0].node() |
|
523 |
|
524 files = [] |
|
525 parity = paritygen(self.stripecount) |
|
526 for f in ctx.files(): |
|
527 files.append(tmpl("filenodelink", |
|
528 node=hex(n), file=f, |
|
529 parity=parity.next())) |
|
530 |
|
531 def diff(**map): |
|
532 yield self.diff(tmpl, p1, n, None) |
|
533 |
|
534 return tmpl('changeset', |
|
535 diff=diff, |
|
536 rev=ctx.rev(), |
|
537 node=hex(n), |
|
538 parent=webutil.siblings(parents), |
|
539 child=webutil.siblings(ctx.children()), |
|
540 changesettag=showtags, |
|
541 author=ctx.user(), |
|
542 desc=ctx.description(), |
|
543 date=ctx.date(), |
|
544 files=files, |
|
545 archives=self.archivelist(hex(n)), |
|
546 tags=webutil.nodetagsdict(self.repo, n), |
|
547 branch=webutil.nodebranchnodefault(ctx), |
|
548 inbranch=webutil.nodeinbranch(self.repo, ctx), |
|
549 branches=webutil.nodebranchdict(self.repo, ctx)) |
|
550 |
|
551 def filelog(self, tmpl, fctx): |
|
552 f = fctx.path() |
|
553 fl = fctx.filelog() |
|
554 count = fl.count() |
|
555 pagelen = self.maxshortchanges |
|
556 pos = fctx.filerev() |
|
557 start = max(0, pos - pagelen + 1) |
|
558 end = min(count, start + pagelen) |
|
559 pos = end - 1 |
|
560 parity = paritygen(self.stripecount, offset=start-end) |
|
561 |
|
562 def entries(limit=0, **map): |
|
563 l = [] |
|
564 |
|
565 for i in xrange(start, end): |
|
566 ctx = fctx.filectx(i) |
|
567 n = fl.node(i) |
|
568 |
|
569 l.insert(0, {"parity": parity.next(), |
|
570 "filerev": i, |
|
571 "file": f, |
|
572 "node": hex(ctx.node()), |
|
573 "author": ctx.user(), |
|
574 "date": ctx.date(), |
|
575 "rename": webutil.renamelink(fl, n), |
|
576 "parent": webutil.siblings(fctx.parents()), |
|
577 "child": webutil.siblings(fctx.children()), |
|
578 "desc": ctx.description()}) |
|
579 |
|
580 if limit > 0: |
|
581 l = l[:limit] |
|
582 |
|
583 for e in l: |
|
584 yield e |
|
585 |
|
586 nodefunc = lambda x: fctx.filectx(fileid=x) |
|
587 nav = revnavgen(pos, pagelen, count, nodefunc) |
|
588 return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav, |
|
589 entries=lambda **x: entries(limit=0, **x), |
|
590 latestentry=lambda **x: entries(limit=1, **x)) |
|
591 |
|
592 def filerevision(self, tmpl, fctx): |
|
593 f = fctx.path() |
|
594 text = fctx.data() |
|
595 fl = fctx.filelog() |
|
596 n = fctx.filenode() |
|
597 parity = paritygen(self.stripecount) |
|
598 |
|
599 if util.binary(text): |
|
600 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream' |
|
601 text = '(binary:%s)' % mt |
|
602 |
|
603 def lines(): |
|
604 for lineno, t in enumerate(text.splitlines(1)): |
|
605 yield {"line": t, |
|
606 "lineid": "l%d" % (lineno + 1), |
|
607 "linenumber": "% 6d" % (lineno + 1), |
|
608 "parity": parity.next()} |
|
609 |
|
610 return tmpl("filerevision", |
|
611 file=f, |
|
612 path=_up(f), |
|
613 text=lines(), |
|
614 rev=fctx.rev(), |
|
615 node=hex(fctx.node()), |
|
616 author=fctx.user(), |
|
617 date=fctx.date(), |
|
618 desc=fctx.description(), |
|
619 branch=webutil.nodebranchnodefault(fctx), |
|
620 parent=webutil.siblings(fctx.parents()), |
|
621 child=webutil.siblings(fctx.children()), |
|
622 rename=webutil.renamelink(fl, n), |
|
623 permissions=fctx.manifest().flags(f)) |
|
624 |
|
625 def fileannotate(self, tmpl, fctx): |
|
626 f = fctx.path() |
|
627 n = fctx.filenode() |
|
628 fl = fctx.filelog() |
|
629 parity = paritygen(self.stripecount) |
|
630 |
|
631 def annotate(**map): |
|
632 last = None |
|
633 if util.binary(fctx.data()): |
|
634 mt = (mimetypes.guess_type(fctx.path())[0] |
|
635 or 'application/octet-stream') |
|
636 lines = enumerate([((fctx.filectx(fctx.filerev()), 1), |
|
637 '(binary:%s)' % mt)]) |
|
638 else: |
|
639 lines = enumerate(fctx.annotate(follow=True, linenumber=True)) |
|
640 for lineno, ((f, targetline), l) in lines: |
|
641 fnode = f.filenode() |
|
642 name = self.repo.ui.shortuser(f.user()) |
|
643 |
|
644 if last != fnode: |
|
645 last = fnode |
|
646 |
|
647 yield {"parity": parity.next(), |
|
648 "node": hex(f.node()), |
|
649 "rev": f.rev(), |
|
650 "author": name, |
|
651 "file": f.path(), |
|
652 "targetline": targetline, |
|
653 "line": l, |
|
654 "lineid": "l%d" % (lineno + 1), |
|
655 "linenumber": "% 6d" % (lineno + 1)} |
|
656 |
|
657 return tmpl("fileannotate", |
|
658 file=f, |
|
659 annotate=annotate, |
|
660 path=_up(f), |
|
661 rev=fctx.rev(), |
|
662 node=hex(fctx.node()), |
|
663 author=fctx.user(), |
|
664 date=fctx.date(), |
|
665 desc=fctx.description(), |
|
666 rename=webutil.renamelink(fl, n), |
|
667 branch=webutil.nodebranchnodefault(fctx), |
|
668 parent=webutil.siblings(fctx.parents()), |
|
669 child=webutil.siblings(fctx.children()), |
|
670 permissions=fctx.manifest().flags(f)) |
|
671 |
|
672 def manifest(self, tmpl, ctx, path): |
|
673 mf = ctx.manifest() |
|
674 node = ctx.node() |
|
675 |
|
676 files = {} |
|
677 parity = paritygen(self.stripecount) |
|
678 |
|
679 if path and path[-1] != "/": |
|
680 path += "/" |
|
681 l = len(path) |
|
682 abspath = "/" + path |
|
683 |
|
684 for f, n in mf.items(): |
|
685 if f[:l] != path: |
|
686 continue |
|
687 remain = f[l:] |
|
688 if "/" in remain: |
|
689 short = remain[:remain.index("/") + 1] # bleah |
|
690 files[short] = (f, None) |
|
691 else: |
|
692 short = os.path.basename(remain) |
|
693 files[short] = (f, n) |
|
694 |
|
695 if not files: |
|
696 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path) |
|
697 |
|
698 def filelist(**map): |
|
699 fl = files.keys() |
|
700 fl.sort() |
|
701 for f in fl: |
|
702 full, fnode = files[f] |
|
703 if not fnode: |
|
704 continue |
|
705 |
|
706 fctx = ctx.filectx(full) |
|
707 yield {"file": full, |
|
708 "parity": parity.next(), |
|
709 "basename": f, |
|
710 "date": fctx.changectx().date(), |
|
711 "size": fctx.size(), |
|
712 "permissions": mf.flags(full)} |
|
713 |
|
714 def dirlist(**map): |
|
715 fl = files.keys() |
|
716 fl.sort() |
|
717 for f in fl: |
|
718 full, fnode = files[f] |
|
719 if fnode: |
|
720 continue |
|
721 |
|
722 yield {"parity": parity.next(), |
|
723 "path": "%s%s" % (abspath, f), |
|
724 "basename": f[:-1]} |
|
725 |
|
726 return tmpl("manifest", |
|
727 rev=ctx.rev(), |
|
728 node=hex(node), |
|
729 path=abspath, |
|
730 up=_up(abspath), |
|
731 upparity=parity.next(), |
|
732 fentries=filelist, |
|
733 dentries=dirlist, |
|
734 archives=self.archivelist(hex(node)), |
|
735 tags=webutil.nodetagsdict(self.repo, node), |
|
736 inbranch=webutil.nodeinbranch(self.repo, ctx), |
|
737 branches=webutil.nodebranchdict(self.repo, ctx)) |
|
738 |
|
739 def tags(self, tmpl): |
|
740 i = self.repo.tagslist() |
|
741 i.reverse() |
|
742 parity = paritygen(self.stripecount) |
|
743 |
|
744 def entries(notip=False,limit=0, **map): |
|
745 count = 0 |
|
746 for k, n in i: |
|
747 if notip and k == "tip": |
|
748 continue |
|
749 if limit > 0 and count >= limit: |
|
750 continue |
|
751 count = count + 1 |
|
752 yield {"parity": parity.next(), |
|
753 "tag": k, |
|
754 "date": self.repo.changectx(n).date(), |
|
755 "node": hex(n)} |
|
756 |
|
757 return tmpl("tags", |
|
758 node=hex(self.repo.changelog.tip()), |
|
759 entries=lambda **x: entries(False,0, **x), |
|
760 entriesnotip=lambda **x: entries(True,0, **x), |
|
761 latestentry=lambda **x: entries(True,1, **x)) |
|
762 |
|
763 def summary(self, tmpl): |
|
764 i = self.repo.tagslist() |
|
765 i.reverse() |
|
766 |
|
767 def tagentries(**map): |
|
768 parity = paritygen(self.stripecount) |
|
769 count = 0 |
|
770 for k, n in i: |
|
771 if k == "tip": # skip tip |
|
772 continue; |
|
773 |
|
774 count += 1 |
|
775 if count > 10: # limit to 10 tags |
|
776 break; |
|
777 |
|
778 yield tmpl("tagentry", |
|
779 parity=parity.next(), |
|
780 tag=k, |
|
781 node=hex(n), |
|
782 date=self.repo.changectx(n).date()) |
|
783 |
|
784 |
|
785 def branches(**map): |
|
786 parity = paritygen(self.stripecount) |
|
787 |
|
788 b = self.repo.branchtags() |
|
789 l = [(-self.repo.changelog.rev(n), n, t) for t, n in b.items()] |
|
790 l.sort() |
|
791 |
|
792 for r,n,t in l: |
|
793 ctx = self.repo.changectx(n) |
|
794 |
|
795 yield {'parity': parity.next(), |
|
796 'branch': t, |
|
797 'node': hex(n), |
|
798 'date': ctx.date()} |
|
799 |
|
800 def changelist(**map): |
|
801 parity = paritygen(self.stripecount, offset=start-end) |
|
802 l = [] # build a list in forward order for efficiency |
|
803 for i in xrange(start, end): |
|
804 ctx = self.repo.changectx(i) |
|
805 n = ctx.node() |
|
806 hn = hex(n) |
|
807 |
|
808 l.insert(0, tmpl( |
|
809 'shortlogentry', |
|
810 parity=parity.next(), |
|
811 author=ctx.user(), |
|
812 desc=ctx.description(), |
|
813 date=ctx.date(), |
|
814 rev=i, |
|
815 node=hn, |
|
816 tags=webutil.nodetagsdict(self.repo, n), |
|
817 inbranch=webutil.nodeinbranch(self.repo, ctx), |
|
818 branches=webutil.nodebranchdict(self.repo, ctx))) |
|
819 |
|
820 yield l |
|
821 |
|
822 cl = self.repo.changelog |
|
823 count = cl.count() |
|
824 start = max(0, count - self.maxchanges) |
|
825 end = min(count, start + self.maxchanges) |
|
826 |
|
827 return tmpl("summary", |
|
828 desc=self.config("web", "description", "unknown"), |
|
829 owner=get_contact(self.config) or "unknown", |
|
830 lastchange=cl.read(cl.tip())[2], |
|
831 tags=tagentries, |
|
832 branches=branches, |
|
833 shortlog=changelist, |
|
834 node=hex(cl.tip()), |
|
835 archives=self.archivelist("tip")) |
|
836 |
|
837 def filediff(self, tmpl, fctx): |
|
838 n = fctx.node() |
|
839 path = fctx.path() |
|
840 parents = fctx.parents() |
|
841 p1 = parents and parents[0].node() or nullid |
|
842 |
|
843 def diff(**map): |
|
844 yield self.diff(tmpl, p1, n, [path]) |
|
845 |
|
846 return tmpl("filediff", |
|
847 file=path, |
|
848 node=hex(n), |
|
849 rev=fctx.rev(), |
|
850 branch=webutil.nodebranchnodefault(fctx), |
|
851 parent=webutil.siblings(parents), |
|
852 child=webutil.siblings(fctx.children()), |
|
853 diff=diff) |
|
854 |
|
855 archive_specs = { |
361 archive_specs = { |
856 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None), |
362 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None), |
857 'gz': ('application/x-tar', 'tgz', '.tar.gz', None), |
363 'gz': ('application/x-tar', 'tgz', '.tar.gz', None), |
858 'zip': ('application/zip', 'zip', '.zip', None), |
364 'zip': ('application/zip', 'zip', '.zip', None), |
859 } |
365 } |
860 |
366 |
861 def archive(self, tmpl, req, key, type_): |
|
862 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame)) |
|
863 cnode = self.repo.lookup(key) |
|
864 arch_version = key |
|
865 if cnode == key or key == 'tip': |
|
866 arch_version = short(cnode) |
|
867 name = "%s-%s" % (reponame, arch_version) |
|
868 mimetype, artype, extension, encoding = self.archive_specs[type_] |
|
869 headers = [ |
|
870 ('Content-Type', mimetype), |
|
871 ('Content-Disposition', 'attachment; filename=%s%s' % |
|
872 (name, extension)) |
|
873 ] |
|
874 if encoding: |
|
875 headers.append(('Content-Encoding', encoding)) |
|
876 req.header(headers) |
|
877 req.respond(HTTP_OK) |
|
878 archival.archive(self.repo, req, cnode, artype, prefix=name) |
|
879 |
|
880 def check_perm(self, req, op, default): |
367 def check_perm(self, req, op, default): |
881 '''check permission for operation based on user auth. |
368 '''check permission for operation based on user auth. |
882 return true if op allowed, else false. |
369 return true if op allowed, else false. |
883 default is policy to use if no config given.''' |
370 default is policy to use if no config given.''' |
884 |
371 |