comparison mercurial/obsolete.py @ 33143:d09ae850296d

obsutil: move 'exclusivemarkers' to the new modules We have a new 'obsutil' module now. We move the high level utility there to bring 'obsolete.py' back to a more reasonable size.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 27 Jun 2017 01:11:56 +0200
parents 4f49810a1011
children d0e5bf12f314
comparison
equal deleted inserted replaced
33142:4f49810a1011 33143:d09ae850296d
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 """
969 If <nodes> is specified, only markers "relevant" to those nodes are are 844 If <nodes> is specified, only markers "relevant" to those nodes are are
970 returned""" 845 returned"""
971 if nodes is None: 846 if nodes is None:
972 rawmarkers = repo.obsstore 847 rawmarkers = repo.obsstore
973 elif exclusive: 848 elif exclusive:
974 rawmarkers = exclusivemarkers(repo, nodes) 849 rawmarkers = obsutil.exclusivemarkers(repo, nodes)
975 else: 850 else:
976 rawmarkers = repo.obsstore.relevantmarkers(nodes) 851 rawmarkers = repo.obsstore.relevantmarkers(nodes)
977 852
978 for markerdata in rawmarkers: 853 for markerdata in rawmarkers:
979 yield marker(repo, markerdata) 854 yield marker(repo, markerdata)
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)