769 if store and readonly: |
769 if store and readonly: |
770 ui.warn(_('obsolete feature not enabled but %i markers found!\n') |
770 ui.warn(_('obsolete feature not enabled but %i markers found!\n') |
771 % len(list(store))) |
771 % len(list(store))) |
772 return store |
772 return store |
773 |
773 |
774 def _filterprunes(markers): |
|
775 """return a set with no prune markers""" |
|
776 return set(m for m in markers if m[1]) |
|
777 |
|
778 def exclusivemarkers(repo, nodes): |
|
779 """set of markers relevant to "nodes" but no other locally-known nodes |
|
780 |
|
781 This function compute the set of markers "exclusive" to a locally-known |
|
782 node. This means we walk the markers starting from <nodes> until we reach a |
|
783 locally-known precursors outside of <nodes>. Element of <nodes> with |
|
784 locally-known successors outside of <nodes> are ignored (since their |
|
785 precursors markers are also relevant to these successors). |
|
786 |
|
787 For example: |
|
788 |
|
789 # (A0 rewritten as A1) |
|
790 # |
|
791 # A0 <-1- A1 # Marker "1" is exclusive to A1 |
|
792 |
|
793 or |
|
794 |
|
795 # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally) |
|
796 # |
|
797 # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1 |
|
798 |
|
799 or |
|
800 |
|
801 # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence)) |
|
802 # |
|
803 # <-2- A1 # Marker "2" is exclusive to A0,A1 |
|
804 # / |
|
805 # <-1- A0 |
|
806 # \ |
|
807 # <-3- A2 # Marker "3" is exclusive to A0,A2 |
|
808 # |
|
809 # in addition: |
|
810 # |
|
811 # Markers "2,3" are exclusive to A1,A2 |
|
812 # Markers "1,2,3" are exclusive to A0,A1,A2 |
|
813 |
|
814 See test/test-obsolete-bundle-strip.t for more examples. |
|
815 |
|
816 An example usage is strip. When stripping a changeset, we also want to |
|
817 strip the markers exclusive to this changeset. Otherwise we would have |
|
818 "dangling"" obsolescence markers from its precursors: Obsolescence markers |
|
819 marking a node as obsolete without any successors available locally. |
|
820 |
|
821 As for relevant markers, the prune markers for children will be followed. |
|
822 Of course, they will only be followed if the pruned children is |
|
823 locally-known. Since the prune markers are relevant to the pruned node. |
|
824 However, while prune markers are considered relevant to the parent of the |
|
825 pruned changesets, prune markers for locally-known changeset (with no |
|
826 successors) are considered exclusive to the pruned nodes. This allows |
|
827 to strip the prune markers (with the rest of the exclusive chain) alongside |
|
828 the pruned changesets. |
|
829 """ |
|
830 # running on a filtered repository would be dangerous as markers could be |
|
831 # reported as exclusive when they are relevant for other filtered nodes. |
|
832 unfi = repo.unfiltered() |
|
833 |
|
834 # shortcut to various useful item |
|
835 nm = unfi.changelog.nodemap |
|
836 precursorsmarkers = unfi.obsstore.precursors |
|
837 successormarkers = unfi.obsstore.successors |
|
838 childrenmarkers = unfi.obsstore.children |
|
839 |
|
840 # exclusive markers (return of the function) |
|
841 exclmarkers = set() |
|
842 # we need fast membership testing |
|
843 nodes = set(nodes) |
|
844 # looking for head in the obshistory |
|
845 # |
|
846 # XXX we are ignoring all issues in regard with cycle for now. |
|
847 stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))] |
|
848 stack.sort() |
|
849 # nodes already stacked |
|
850 seennodes = set(stack) |
|
851 while stack: |
|
852 current = stack.pop() |
|
853 # fetch precursors markers |
|
854 markers = list(precursorsmarkers.get(current, ())) |
|
855 # extend the list with prune markers |
|
856 for mark in successormarkers.get(current, ()): |
|
857 if not mark[1]: |
|
858 markers.append(mark) |
|
859 # and markers from children (looking for prune) |
|
860 for mark in childrenmarkers.get(current, ()): |
|
861 if not mark[1]: |
|
862 markers.append(mark) |
|
863 # traverse the markers |
|
864 for mark in markers: |
|
865 if mark in exclmarkers: |
|
866 # markers already selected |
|
867 continue |
|
868 |
|
869 # If the markers is about the current node, select it |
|
870 # |
|
871 # (this delay the addition of markers from children) |
|
872 if mark[1] or mark[0] == current: |
|
873 exclmarkers.add(mark) |
|
874 |
|
875 # should we keep traversing through the precursors? |
|
876 prec = mark[0] |
|
877 |
|
878 # nodes in the stack or already processed |
|
879 if prec in seennodes: |
|
880 continue |
|
881 |
|
882 # is this a locally known node ? |
|
883 known = prec in nm |
|
884 # if locally-known and not in the <nodes> set the traversal |
|
885 # stop here. |
|
886 if known and prec not in nodes: |
|
887 continue |
|
888 |
|
889 # do not keep going if there are unselected markers pointing to this |
|
890 # nodes. If we end up traversing these unselected markers later the |
|
891 # node will be taken care of at that point. |
|
892 precmarkers = _filterprunes(successormarkers.get(prec)) |
|
893 if precmarkers.issubset(exclmarkers): |
|
894 seennodes.add(prec) |
|
895 stack.append(prec) |
|
896 |
|
897 return exclmarkers |
|
898 |
|
899 def commonversion(versions): |
774 def commonversion(versions): |
900 """Return the newest version listed in both versions and our local formats. |
775 """Return the newest version listed in both versions and our local formats. |
901 |
776 |
902 Returns None if no common version exists. |
777 Returns None if no common version exists. |
903 """ |
778 """ |
1060 mutable = [c.node() for c in foreground if c.mutable()] |
935 mutable = [c.node() for c in foreground if c.mutable()] |
1061 succs.update(allsuccessors(repo.obsstore, mutable)) |
936 succs.update(allsuccessors(repo.obsstore, mutable)) |
1062 known = (n for n in succs if n in nm) |
937 known = (n for n in succs if n in nm) |
1063 foreground = set(repo.set('%ln::', known)) |
938 foreground = set(repo.set('%ln::', known)) |
1064 return set(c.node() for c in foreground) |
939 return set(c.node() for c in foreground) |
|
940 |
|
941 def exclusivemarkers(repo, nodes): |
|
942 movemsg = 'obsolete.exclusivemarkers moved to obsutil.exclusivemarkers' |
|
943 repo.ui.deprecwarn(movemsg, '4.3') |
|
944 return obsutil.exclusivemarkers(repo, nodes) |
1065 |
945 |
1066 def successorssets(repo, initialnode, cache=None): |
946 def successorssets(repo, initialnode, cache=None): |
1067 movemsg = 'obsolete.successorssets moved to obsutil.successorssets' |
947 movemsg = 'obsolete.successorssets moved to obsutil.successorssets' |
1068 repo.ui.deprecwarn(movemsg, '4.3') |
948 repo.ui.deprecwarn(movemsg, '4.3') |
1069 return obsutil.successorssets(repo, initialnode, cache=cache) |
949 return obsutil.successorssets(repo, initialnode, cache=cache) |