Show More
@@ -771,131 +771,6 def makestore(ui, repo): | |||
|
771 | 771 | % len(list(store))) |
|
772 | 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 | 774 | def commonversion(versions): |
|
900 | 775 | """Return the newest version listed in both versions and our local formats. |
|
901 | 776 | |
@@ -971,7 +846,7 def getmarkers(repo, nodes=None, exclusi | |||
|
971 | 846 | if nodes is None: |
|
972 | 847 | rawmarkers = repo.obsstore |
|
973 | 848 | elif exclusive: |
|
974 | rawmarkers = exclusivemarkers(repo, nodes) | |
|
849 | rawmarkers = obsutil.exclusivemarkers(repo, nodes) | |
|
975 | 850 | else: |
|
976 | 851 | rawmarkers = repo.obsstore.relevantmarkers(nodes) |
|
977 | 852 | |
@@ -1063,6 +938,11 def foreground(repo, nodes): | |||
|
1063 | 938 | foreground = set(repo.set('%ln::', known)) |
|
1064 | 939 | return set(c.node() for c in foreground) |
|
1065 | 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) | |
|
945 | ||
|
1066 | 946 | def successorssets(repo, initialnode, cache=None): |
|
1067 | 947 | movemsg = 'obsolete.successorssets moved to obsutil.successorssets' |
|
1068 | 948 | repo.ui.deprecwarn(movemsg, '4.3') |
@@ -35,6 +35,131 def closestpredecessors(repo, nodeid): | |||
|
35 | 35 | else: |
|
36 | 36 | stack.append(precnodeid) |
|
37 | 37 | |
|
38 | def _filterprunes(markers): | |
|
39 | """return a set with no prune markers""" | |
|
40 | return set(m for m in markers if m[1]) | |
|
41 | ||
|
42 | def exclusivemarkers(repo, nodes): | |
|
43 | """set of markers relevant to "nodes" but no other locally-known nodes | |
|
44 | ||
|
45 | This function compute the set of markers "exclusive" to a locally-known | |
|
46 | node. This means we walk the markers starting from <nodes> until we reach a | |
|
47 | locally-known precursors outside of <nodes>. Element of <nodes> with | |
|
48 | locally-known successors outside of <nodes> are ignored (since their | |
|
49 | precursors markers are also relevant to these successors). | |
|
50 | ||
|
51 | For example: | |
|
52 | ||
|
53 | # (A0 rewritten as A1) | |
|
54 | # | |
|
55 | # A0 <-1- A1 # Marker "1" is exclusive to A1 | |
|
56 | ||
|
57 | or | |
|
58 | ||
|
59 | # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally) | |
|
60 | # | |
|
61 | # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1 | |
|
62 | ||
|
63 | or | |
|
64 | ||
|
65 | # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence)) | |
|
66 | # | |
|
67 | # <-2- A1 # Marker "2" is exclusive to A0,A1 | |
|
68 | # / | |
|
69 | # <-1- A0 | |
|
70 | # \ | |
|
71 | # <-3- A2 # Marker "3" is exclusive to A0,A2 | |
|
72 | # | |
|
73 | # in addition: | |
|
74 | # | |
|
75 | # Markers "2,3" are exclusive to A1,A2 | |
|
76 | # Markers "1,2,3" are exclusive to A0,A1,A2 | |
|
77 | ||
|
78 | See test/test-obsolete-bundle-strip.t for more examples. | |
|
79 | ||
|
80 | An example usage is strip. When stripping a changeset, we also want to | |
|
81 | strip the markers exclusive to this changeset. Otherwise we would have | |
|
82 | "dangling"" obsolescence markers from its precursors: Obsolescence markers | |
|
83 | marking a node as obsolete without any successors available locally. | |
|
84 | ||
|
85 | As for relevant markers, the prune markers for children will be followed. | |
|
86 | Of course, they will only be followed if the pruned children is | |
|
87 | locally-known. Since the prune markers are relevant to the pruned node. | |
|
88 | However, while prune markers are considered relevant to the parent of the | |
|
89 | pruned changesets, prune markers for locally-known changeset (with no | |
|
90 | successors) are considered exclusive to the pruned nodes. This allows | |
|
91 | to strip the prune markers (with the rest of the exclusive chain) alongside | |
|
92 | the pruned changesets. | |
|
93 | """ | |
|
94 | # running on a filtered repository would be dangerous as markers could be | |
|
95 | # reported as exclusive when they are relevant for other filtered nodes. | |
|
96 | unfi = repo.unfiltered() | |
|
97 | ||
|
98 | # shortcut to various useful item | |
|
99 | nm = unfi.changelog.nodemap | |
|
100 | precursorsmarkers = unfi.obsstore.precursors | |
|
101 | successormarkers = unfi.obsstore.successors | |
|
102 | childrenmarkers = unfi.obsstore.children | |
|
103 | ||
|
104 | # exclusive markers (return of the function) | |
|
105 | exclmarkers = set() | |
|
106 | # we need fast membership testing | |
|
107 | nodes = set(nodes) | |
|
108 | # looking for head in the obshistory | |
|
109 | # | |
|
110 | # XXX we are ignoring all issues in regard with cycle for now. | |
|
111 | stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))] | |
|
112 | stack.sort() | |
|
113 | # nodes already stacked | |
|
114 | seennodes = set(stack) | |
|
115 | while stack: | |
|
116 | current = stack.pop() | |
|
117 | # fetch precursors markers | |
|
118 | markers = list(precursorsmarkers.get(current, ())) | |
|
119 | # extend the list with prune markers | |
|
120 | for mark in successormarkers.get(current, ()): | |
|
121 | if not mark[1]: | |
|
122 | markers.append(mark) | |
|
123 | # and markers from children (looking for prune) | |
|
124 | for mark in childrenmarkers.get(current, ()): | |
|
125 | if not mark[1]: | |
|
126 | markers.append(mark) | |
|
127 | # traverse the markers | |
|
128 | for mark in markers: | |
|
129 | if mark in exclmarkers: | |
|
130 | # markers already selected | |
|
131 | continue | |
|
132 | ||
|
133 | # If the markers is about the current node, select it | |
|
134 | # | |
|
135 | # (this delay the addition of markers from children) | |
|
136 | if mark[1] or mark[0] == current: | |
|
137 | exclmarkers.add(mark) | |
|
138 | ||
|
139 | # should we keep traversing through the precursors? | |
|
140 | prec = mark[0] | |
|
141 | ||
|
142 | # nodes in the stack or already processed | |
|
143 | if prec in seennodes: | |
|
144 | continue | |
|
145 | ||
|
146 | # is this a locally known node ? | |
|
147 | known = prec in nm | |
|
148 | # if locally-known and not in the <nodes> set the traversal | |
|
149 | # stop here. | |
|
150 | if known and prec not in nodes: | |
|
151 | continue | |
|
152 | ||
|
153 | # do not keep going if there are unselected markers pointing to this | |
|
154 | # nodes. If we end up traversing these unselected markers later the | |
|
155 | # node will be taken care of at that point. | |
|
156 | precmarkers = _filterprunes(successormarkers.get(prec)) | |
|
157 | if precmarkers.issubset(exclmarkers): | |
|
158 | seennodes.add(prec) | |
|
159 | stack.append(prec) | |
|
160 | ||
|
161 | return exclmarkers | |
|
162 | ||
|
38 | 163 | def successorssets(repo, initialnode, cache=None): |
|
39 | 164 | """Return set of all latest successors of initial nodes |
|
40 | 165 |
@@ -20,6 +20,7 from . import ( | |||
|
20 | 20 | error, |
|
21 | 21 | exchange, |
|
22 | 22 | obsolete, |
|
23 | obsutil, | |
|
23 | 24 | util, |
|
24 | 25 | ) |
|
25 | 26 | |
@@ -132,7 +133,7 def strip(ui, repo, nodelist, backup=Tru | |||
|
132 | 133 | |
|
133 | 134 | stripobsidx = obsmarkers = () |
|
134 | 135 | if repo.ui.configbool('devel', 'strip-obsmarkers', True): |
|
135 |
obsmarkers = obs |
|
|
136 | obsmarkers = obsutil.exclusivemarkers(repo, stripbases) | |
|
136 | 137 | if obsmarkers: |
|
137 | 138 | stripobsidx = [i for i, m in enumerate(repo.obsstore) |
|
138 | 139 | if m in obsmarkers] |
General Comments 0
You need to be logged in to leave comments.
Login now