19 |
19 |
20 # Phony node value to stand-in for new files in some uses of |
20 # Phony node value to stand-in for new files in some uses of |
21 # manifests. Manifests support 21-byte hashes for nodes which are |
21 # manifests. Manifests support 21-byte hashes for nodes which are |
22 # dirty in the working copy. |
22 # dirty in the working copy. |
23 _newnode = '!' * 21 |
23 _newnode = '!' * 21 |
24 |
|
25 def _adjustlinkrev(repo, path, filelog, fnode, srcrev, inclusive=False): |
|
26 """return the first ancestor of <srcrev> introducting <fnode> |
|
27 |
|
28 If the linkrev of the file revision does not point to an ancestor of |
|
29 srcrev, we'll walk down the ancestors until we find one introducing this |
|
30 file revision. |
|
31 |
|
32 :repo: a localrepository object (used to access changelog and manifest) |
|
33 :path: the file path |
|
34 :fnode: the nodeid of the file revision |
|
35 :filelog: the filelog of this path |
|
36 :srcrev: the changeset revision we search ancestors from |
|
37 :inclusive: if true, the src revision will also be checked |
|
38 """ |
|
39 cl = repo.unfiltered().changelog |
|
40 ma = repo.manifest |
|
41 # fetch the linkrev |
|
42 fr = filelog.rev(fnode) |
|
43 lkr = filelog.linkrev(fr) |
|
44 # check if this linkrev is an ancestor of srcrev |
|
45 anc = cl.ancestors([srcrev], lkr, inclusive=inclusive) |
|
46 if lkr not in anc: |
|
47 for a in anc: |
|
48 ac = cl.read(a) # get changeset data (we avoid object creation). |
|
49 if path in ac[3]: # checking the 'files' field. |
|
50 # The file has been touched, check if the content is similar |
|
51 # to the one we search for. |
|
52 if fnode == ma.readfast(ac[0]).get(path): |
|
53 return a |
|
54 # In theory, we should never get out of that loop without a result. But |
|
55 # if manifest uses a buggy file revision (not children of the one it |
|
56 # replaces) we could. Such a buggy situation will likely result is crash |
|
57 # somewhere else at to some point. |
|
58 return lkr |
|
59 |
24 |
60 class basectx(object): |
25 class basectx(object): |
61 """A basectx object represents the common logic for its children: |
26 """A basectx object represents the common logic for its children: |
62 changectx: read-only context that is already present in the repo, |
27 changectx: read-only context that is already present in the repo, |
63 workingctx: a context that represents the working directory and can |
28 workingctx: a context that represents the working directory and can |
779 or self.size() == fctx.size()): |
744 or self.size() == fctx.size()): |
780 return self._filelog.cmp(self._filenode, fctx.data()) |
745 return self._filelog.cmp(self._filenode, fctx.data()) |
781 |
746 |
782 return True |
747 return True |
783 |
748 |
|
749 def _adjustlinkrev(self, path, filelog, fnode, srcrev, inclusive=False): |
|
750 """return the first ancestor of <srcrev> introducting <fnode> |
|
751 |
|
752 If the linkrev of the file revision does not point to an ancestor of |
|
753 srcrev, we'll walk down the ancestors until we find one introducing |
|
754 this file revision. |
|
755 |
|
756 :repo: a localrepository object (used to access changelog and manifest) |
|
757 :path: the file path |
|
758 :fnode: the nodeid of the file revision |
|
759 :filelog: the filelog of this path |
|
760 :srcrev: the changeset revision we search ancestors from |
|
761 :inclusive: if true, the src revision will also be checked |
|
762 """ |
|
763 repo = self._repo |
|
764 cl = repo.unfiltered().changelog |
|
765 ma = repo.manifest |
|
766 # fetch the linkrev |
|
767 fr = filelog.rev(fnode) |
|
768 lkr = filelog.linkrev(fr) |
|
769 # check if this linkrev is an ancestor of srcrev |
|
770 anc = cl.ancestors([srcrev], lkr, inclusive=inclusive) |
|
771 if lkr not in anc: |
|
772 for a in anc: |
|
773 ac = cl.read(a) # get changeset data (we avoid object creation) |
|
774 if path in ac[3]: # checking the 'files' field. |
|
775 # The file has been touched, check if the content is |
|
776 # similar to the one we search for. |
|
777 if fnode == ma.readfast(ac[0]).get(path): |
|
778 return a |
|
779 # In theory, we should never get out of that loop without a result. |
|
780 # But if manifest uses a buggy file revision (not children of the |
|
781 # one it replaces) we could. Such a buggy situation will likely |
|
782 # result is crash somewhere else at to some point. |
|
783 return lkr |
|
784 |
784 def introrev(self): |
785 def introrev(self): |
785 """return the rev of the changeset which introduced this file revision |
786 """return the rev of the changeset which introduced this file revision |
786 |
787 |
787 This method is different from linkrev because it take into account the |
788 This method is different from linkrev because it take into account the |
788 changeset the filectx was created from. It ensures the returned |
789 changeset the filectx was created from. It ensures the returned |
793 lkr = self.linkrev() |
794 lkr = self.linkrev() |
794 attrs = vars(self) |
795 attrs = vars(self) |
795 noctx = not ('_changeid' in attrs or '_changectx' in attrs) |
796 noctx = not ('_changeid' in attrs or '_changectx' in attrs) |
796 if noctx or self.rev() == lkr: |
797 if noctx or self.rev() == lkr: |
797 return self.linkrev() |
798 return self.linkrev() |
798 return _adjustlinkrev(self._repo, self._path, self._filelog, |
799 return self._adjustlinkrev(self._path, self._filelog, self._filenode, |
799 self._filenode, self.rev(), inclusive=True) |
800 self.rev(), inclusive=True) |
800 |
801 |
801 def parents(self): |
802 def parents(self): |
802 _path = self._path |
803 _path = self._path |
803 fl = self._filelog |
804 fl = self._filelog |
804 parents = self._filelog.parents(self._filenode) |
805 parents = self._filelog.parents(self._filenode) |
820 for path, fnode, l in pl: |
821 for path, fnode, l in pl: |
821 if '_changeid' in vars(self) or '_changectx' in vars(self): |
822 if '_changeid' in vars(self) or '_changectx' in vars(self): |
822 # If self is associated with a changeset (probably explicitly |
823 # If self is associated with a changeset (probably explicitly |
823 # fed), ensure the created filectx is associated with a |
824 # fed), ensure the created filectx is associated with a |
824 # changeset that is an ancestor of self.changectx. |
825 # changeset that is an ancestor of self.changectx. |
825 rev = _adjustlinkrev(self._repo, path, l, fnode, self.rev()) |
826 rev = self._adjustlinkrev(path, l, fnode, self.rev()) |
826 fctx = filectx(self._repo, path, fileid=fnode, filelog=l, |
827 fctx = filectx(self._repo, path, fileid=fnode, filelog=l, |
827 changeid=rev) |
828 changeid=rev) |
828 else: |
829 else: |
829 fctx = filectx(self._repo, path, fileid=fnode, filelog=l) |
830 fctx = filectx(self._repo, path, fileid=fnode, filelog=l) |
830 ret.append(fctx) |
831 ret.append(fctx) |