557 p = self.parents() |
557 p = self.parents() |
558 if len(p) == 2: |
558 if len(p) == 2: |
559 return p[1] |
559 return p[1] |
560 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog) |
560 return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog) |
561 |
561 |
562 class filectx(basefilectx): |
|
563 """A filecontext object makes access to data related to a particular |
|
564 filerevision convenient.""" |
|
565 def __init__(self, repo, path, changeid=None, fileid=None, |
|
566 filelog=None, changectx=None): |
|
567 """changeid can be a changeset revision, node, or tag. |
|
568 fileid can be a file revision or node.""" |
|
569 self._repo = repo |
|
570 self._path = path |
|
571 |
|
572 assert (changeid is not None |
|
573 or fileid is not None |
|
574 or changectx is not None), \ |
|
575 ("bad args: changeid=%r, fileid=%r, changectx=%r" |
|
576 % (changeid, fileid, changectx)) |
|
577 |
|
578 if filelog is not None: |
|
579 self._filelog = filelog |
|
580 |
|
581 if changeid is not None: |
|
582 self._changeid = changeid |
|
583 if changectx is not None: |
|
584 self._changectx = changectx |
|
585 if fileid is not None: |
|
586 self._fileid = fileid |
|
587 |
|
588 @propertycache |
|
589 def _changectx(self): |
|
590 try: |
|
591 return changectx(self._repo, self._changeid) |
|
592 except error.RepoLookupError: |
|
593 # Linkrev may point to any revision in the repository. When the |
|
594 # repository is filtered this may lead to `filectx` trying to build |
|
595 # `changectx` for filtered revision. In such case we fallback to |
|
596 # creating `changectx` on the unfiltered version of the reposition. |
|
597 # This fallback should not be an issue because `changectx` from |
|
598 # `filectx` are not used in complex operations that care about |
|
599 # filtering. |
|
600 # |
|
601 # This fallback is a cheap and dirty fix that prevent several |
|
602 # crashes. It does not ensure the behavior is correct. However the |
|
603 # behavior was not correct before filtering either and "incorrect |
|
604 # behavior" is seen as better as "crash" |
|
605 # |
|
606 # Linkrevs have several serious troubles with filtering that are |
|
607 # complicated to solve. Proper handling of the issue here should be |
|
608 # considered when solving linkrev issue are on the table. |
|
609 return changectx(self._repo.unfiltered(), self._changeid) |
|
610 |
|
611 def filectx(self, fileid): |
|
612 '''opens an arbitrary revision of the file without |
|
613 opening a new filelog''' |
|
614 return filectx(self._repo, self._path, fileid=fileid, |
|
615 filelog=self._filelog) |
|
616 |
|
617 def data(self): |
|
618 return self._filelog.read(self._filenode) |
|
619 def size(self): |
|
620 return self._filelog.size(self._filerev) |
|
621 |
|
622 def renamed(self): |
|
623 """check if file was actually renamed in this changeset revision |
|
624 |
|
625 If rename logged in file revision, we report copy for changeset only |
|
626 if file revisions linkrev points back to the changeset in question |
|
627 or both changeset parents contain different file revisions. |
|
628 """ |
|
629 |
|
630 renamed = self._filelog.renamed(self._filenode) |
|
631 if not renamed: |
|
632 return renamed |
|
633 |
|
634 if self.rev() == self.linkrev(): |
|
635 return renamed |
|
636 |
|
637 name = self.path() |
|
638 fnode = self._filenode |
|
639 for p in self._changectx.parents(): |
|
640 try: |
|
641 if fnode == p.filenode(name): |
|
642 return None |
|
643 except error.LookupError: |
|
644 pass |
|
645 return renamed |
|
646 |
|
647 def children(self): |
|
648 # hard for renames |
|
649 c = self._filelog.children(self._filenode) |
|
650 return [filectx(self._repo, self._path, fileid=x, |
|
651 filelog=self._filelog) for x in c] |
|
652 |
|
653 def annotate(self, follow=False, linenumber=None, diffopts=None): |
562 def annotate(self, follow=False, linenumber=None, diffopts=None): |
654 '''returns a list of tuples of (ctx, line) for each line |
563 '''returns a list of tuples of (ctx, line) for each line |
655 in the file, where ctx is the filectx of the node where |
564 in the file, where ctx is the filectx of the node where |
656 that line was last changed. |
565 that line was last changed. |
657 This returns tuples of ((ctx, linenumber), line) for each line, |
566 This returns tuples of ((ctx, linenumber), line) for each line, |
749 |
658 |
750 hist[f] = curr |
659 hist[f] = curr |
751 pcache[f] = [] |
660 pcache[f] = [] |
752 |
661 |
753 return zip(hist[base][0], hist[base][1].splitlines(True)) |
662 return zip(hist[base][0], hist[base][1].splitlines(True)) |
|
663 |
|
664 class filectx(basefilectx): |
|
665 """A filecontext object makes access to data related to a particular |
|
666 filerevision convenient.""" |
|
667 def __init__(self, repo, path, changeid=None, fileid=None, |
|
668 filelog=None, changectx=None): |
|
669 """changeid can be a changeset revision, node, or tag. |
|
670 fileid can be a file revision or node.""" |
|
671 self._repo = repo |
|
672 self._path = path |
|
673 |
|
674 assert (changeid is not None |
|
675 or fileid is not None |
|
676 or changectx is not None), \ |
|
677 ("bad args: changeid=%r, fileid=%r, changectx=%r" |
|
678 % (changeid, fileid, changectx)) |
|
679 |
|
680 if filelog is not None: |
|
681 self._filelog = filelog |
|
682 |
|
683 if changeid is not None: |
|
684 self._changeid = changeid |
|
685 if changectx is not None: |
|
686 self._changectx = changectx |
|
687 if fileid is not None: |
|
688 self._fileid = fileid |
|
689 |
|
690 @propertycache |
|
691 def _changectx(self): |
|
692 try: |
|
693 return changectx(self._repo, self._changeid) |
|
694 except error.RepoLookupError: |
|
695 # Linkrev may point to any revision in the repository. When the |
|
696 # repository is filtered this may lead to `filectx` trying to build |
|
697 # `changectx` for filtered revision. In such case we fallback to |
|
698 # creating `changectx` on the unfiltered version of the reposition. |
|
699 # This fallback should not be an issue because `changectx` from |
|
700 # `filectx` are not used in complex operations that care about |
|
701 # filtering. |
|
702 # |
|
703 # This fallback is a cheap and dirty fix that prevent several |
|
704 # crashes. It does not ensure the behavior is correct. However the |
|
705 # behavior was not correct before filtering either and "incorrect |
|
706 # behavior" is seen as better as "crash" |
|
707 # |
|
708 # Linkrevs have several serious troubles with filtering that are |
|
709 # complicated to solve. Proper handling of the issue here should be |
|
710 # considered when solving linkrev issue are on the table. |
|
711 return changectx(self._repo.unfiltered(), self._changeid) |
|
712 |
|
713 def filectx(self, fileid): |
|
714 '''opens an arbitrary revision of the file without |
|
715 opening a new filelog''' |
|
716 return filectx(self._repo, self._path, fileid=fileid, |
|
717 filelog=self._filelog) |
|
718 |
|
719 def data(self): |
|
720 return self._filelog.read(self._filenode) |
|
721 def size(self): |
|
722 return self._filelog.size(self._filerev) |
|
723 |
|
724 def renamed(self): |
|
725 """check if file was actually renamed in this changeset revision |
|
726 |
|
727 If rename logged in file revision, we report copy for changeset only |
|
728 if file revisions linkrev points back to the changeset in question |
|
729 or both changeset parents contain different file revisions. |
|
730 """ |
|
731 |
|
732 renamed = self._filelog.renamed(self._filenode) |
|
733 if not renamed: |
|
734 return renamed |
|
735 |
|
736 if self.rev() == self.linkrev(): |
|
737 return renamed |
|
738 |
|
739 name = self.path() |
|
740 fnode = self._filenode |
|
741 for p in self._changectx.parents(): |
|
742 try: |
|
743 if fnode == p.filenode(name): |
|
744 return None |
|
745 except error.LookupError: |
|
746 pass |
|
747 return renamed |
|
748 |
|
749 def children(self): |
|
750 # hard for renames |
|
751 c = self._filelog.children(self._filenode) |
|
752 return [filectx(self._repo, self._path, fileid=x, |
|
753 filelog=self._filelog) for x in c] |
754 |
754 |
755 def ancestor(self, fc2, actx): |
755 def ancestor(self, fc2, actx): |
756 """ |
756 """ |
757 find the common ancestor file context, if any, of self, and fc2 |
757 find the common ancestor file context, if any, of self, and fc2 |
758 |
758 |