769 result, use ``file()``. |
769 result, use ``file()``. |
770 |
770 |
771 The pattern without explicit kind like ``glob:`` is expected to be |
771 The pattern without explicit kind like ``glob:`` is expected to be |
772 relative to the current directory and match against a file exactly |
772 relative to the current directory and match against a file exactly |
773 for efficiency. |
773 for efficiency. |
|
774 |
|
775 If some linkrev points to revisions filtered by the current repoview, we'll |
|
776 work around it to return a non-filtered value. |
774 """ |
777 """ |
775 |
778 |
776 # i18n: "filelog" is a keyword |
779 # i18n: "filelog" is a keyword |
777 pat = getstring(x, _("filelog requires a pattern")) |
780 pat = getstring(x, _("filelog requires a pattern")) |
778 s = set() |
781 s = set() |
|
782 cl = repo.changelog |
779 |
783 |
780 if not matchmod.patkind(pat): |
784 if not matchmod.patkind(pat): |
781 f = pathutil.canonpath(repo.root, repo.getcwd(), pat) |
785 f = pathutil.canonpath(repo.root, repo.getcwd(), pat) |
782 fl = repo.file(f) |
786 files = [f] |
783 for fr in fl: |
|
784 s.add(fl.linkrev(fr)) |
|
785 else: |
787 else: |
786 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None]) |
788 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None]) |
787 for f in repo[None]: |
789 files = (f for f in repo[None] if m(f)) |
788 if m(f): |
790 |
789 fl = repo.file(f) |
791 for f in files: |
790 for fr in fl: |
792 backrevref = {} # final value for: changerev -> filerev |
791 s.add(fl.linkrev(fr)) |
793 lowestchild = {} # lowest known filerev child of a filerev |
|
794 delayed = [] # filerev with filtered linkrev, for post-processing |
|
795 fl = repo.file(f) |
|
796 for fr in list(fl): |
|
797 lkr = rev = fl.linkrev(fr) |
|
798 if rev not in cl: |
|
799 # changerev pointed in linkrev is filtered |
|
800 # record it for post processing. |
|
801 delayed.append((fr, rev)) |
|
802 continue |
|
803 for p in fl.parentrevs(fr): |
|
804 if 0 <= p and p not in lowestchild: |
|
805 lowestchild[p] = fr |
|
806 backrevref[fr] = rev |
|
807 s.add(rev) |
|
808 |
|
809 # Post-processing of all filerevs we skipped because they were |
|
810 # filtered. If such filerevs have known and unfiltered children, this |
|
811 # means they have an unfiltered appearance out there. We'll use linkrev |
|
812 # adjustment to find one of these appearances. The lowest known child |
|
813 # will be used as a starting point because it is the best upper-bound we |
|
814 # have. |
|
815 # |
|
816 # This approach will fail when an unfiltered but linkrev-shadowed |
|
817 # appearance exists in a head changeset without unfiltered filerev |
|
818 # children anywhere. |
|
819 while delayed: |
|
820 # must be a descending iteration. To slowly fill lowest child |
|
821 # information that is of potential use by the next item. |
|
822 fr, rev = delayed.pop() |
|
823 lkr = rev |
|
824 |
|
825 child = lowestchild.get(fr) |
|
826 |
|
827 if child is None: |
|
828 # XXX content could be linkrev-shadowed in a head, but lets |
|
829 # ignore this case for now. |
|
830 continue |
|
831 else: |
|
832 # the lowest known child is a good upper bound |
|
833 childcrev = backrevref[child] |
|
834 # XXX this does not guarantee returning the lowest |
|
835 # introduction of this revision, but this gives a |
|
836 # result which is a good start and will fit in most |
|
837 # cases. We probably need to fix the multiple |
|
838 # introductions case properly (report each |
|
839 # introduction, even for identical file revisions) |
|
840 # once and for all at some point anyway. |
|
841 for p in repo[childcrev][f].parents(): |
|
842 if p.filerev() == fr: |
|
843 rev = p.rev() |
|
844 break |
|
845 if rev == lkr: # no shadowed entry found |
|
846 # XXX This should never happen unless some manifest points |
|
847 # to biggish file revisions (like a revision that uses a |
|
848 # parent that never appears in the manifest ancestors) |
|
849 continue |
|
850 |
|
851 # Fill the data for the next iteration. |
|
852 for p in fl.parentrevs(fr): |
|
853 if 0 <= p and p not in lowestchild: |
|
854 lowestchild[p] = fr |
|
855 backrevref[fr] = rev |
|
856 s.add(rev) |
792 |
857 |
793 return subset & s |
858 return subset & s |
794 |
859 |
795 def first(repo, subset, x): |
860 def first(repo, subset, x): |
796 """``first(set, [n])`` |
861 """``first(set, [n])`` |