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.
--- a/mercurial/obsolete.py Tue Jun 27 01:03:01 2017 +0200
+++ b/mercurial/obsolete.py Tue Jun 27 01:11:56 2017 +0200
@@ -771,131 +771,6 @@
% len(list(store)))
return store
-def _filterprunes(markers):
- """return a set with no prune markers"""
- return set(m for m in markers if m[1])
-
-def exclusivemarkers(repo, nodes):
- """set of markers relevant to "nodes" but no other locally-known nodes
-
- This function compute the set of markers "exclusive" to a locally-known
- node. This means we walk the markers starting from <nodes> until we reach a
- locally-known precursors outside of <nodes>. Element of <nodes> with
- locally-known successors outside of <nodes> are ignored (since their
- precursors markers are also relevant to these successors).
-
- For example:
-
- # (A0 rewritten as A1)
- #
- # A0 <-1- A1 # Marker "1" is exclusive to A1
-
- or
-
- # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally)
- #
- # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1
-
- or
-
- # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence))
- #
- # <-2- A1 # Marker "2" is exclusive to A0,A1
- # /
- # <-1- A0
- # \
- # <-3- A2 # Marker "3" is exclusive to A0,A2
- #
- # in addition:
- #
- # Markers "2,3" are exclusive to A1,A2
- # Markers "1,2,3" are exclusive to A0,A1,A2
-
- See test/test-obsolete-bundle-strip.t for more examples.
-
- An example usage is strip. When stripping a changeset, we also want to
- strip the markers exclusive to this changeset. Otherwise we would have
- "dangling"" obsolescence markers from its precursors: Obsolescence markers
- marking a node as obsolete without any successors available locally.
-
- As for relevant markers, the prune markers for children will be followed.
- Of course, they will only be followed if the pruned children is
- locally-known. Since the prune markers are relevant to the pruned node.
- However, while prune markers are considered relevant to the parent of the
- pruned changesets, prune markers for locally-known changeset (with no
- successors) are considered exclusive to the pruned nodes. This allows
- to strip the prune markers (with the rest of the exclusive chain) alongside
- the pruned changesets.
- """
- # running on a filtered repository would be dangerous as markers could be
- # reported as exclusive when they are relevant for other filtered nodes.
- unfi = repo.unfiltered()
-
- # shortcut to various useful item
- nm = unfi.changelog.nodemap
- precursorsmarkers = unfi.obsstore.precursors
- successormarkers = unfi.obsstore.successors
- childrenmarkers = unfi.obsstore.children
-
- # exclusive markers (return of the function)
- exclmarkers = set()
- # we need fast membership testing
- nodes = set(nodes)
- # looking for head in the obshistory
- #
- # XXX we are ignoring all issues in regard with cycle for now.
- stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))]
- stack.sort()
- # nodes already stacked
- seennodes = set(stack)
- while stack:
- current = stack.pop()
- # fetch precursors markers
- markers = list(precursorsmarkers.get(current, ()))
- # extend the list with prune markers
- for mark in successormarkers.get(current, ()):
- if not mark[1]:
- markers.append(mark)
- # and markers from children (looking for prune)
- for mark in childrenmarkers.get(current, ()):
- if not mark[1]:
- markers.append(mark)
- # traverse the markers
- for mark in markers:
- if mark in exclmarkers:
- # markers already selected
- continue
-
- # If the markers is about the current node, select it
- #
- # (this delay the addition of markers from children)
- if mark[1] or mark[0] == current:
- exclmarkers.add(mark)
-
- # should we keep traversing through the precursors?
- prec = mark[0]
-
- # nodes in the stack or already processed
- if prec in seennodes:
- continue
-
- # is this a locally known node ?
- known = prec in nm
- # if locally-known and not in the <nodes> set the traversal
- # stop here.
- if known and prec not in nodes:
- continue
-
- # do not keep going if there are unselected markers pointing to this
- # nodes. If we end up traversing these unselected markers later the
- # node will be taken care of at that point.
- precmarkers = _filterprunes(successormarkers.get(prec))
- if precmarkers.issubset(exclmarkers):
- seennodes.add(prec)
- stack.append(prec)
-
- return exclmarkers
-
def commonversion(versions):
"""Return the newest version listed in both versions and our local formats.
@@ -971,7 +846,7 @@
if nodes is None:
rawmarkers = repo.obsstore
elif exclusive:
- rawmarkers = exclusivemarkers(repo, nodes)
+ rawmarkers = obsutil.exclusivemarkers(repo, nodes)
else:
rawmarkers = repo.obsstore.relevantmarkers(nodes)
@@ -1063,6 +938,11 @@
foreground = set(repo.set('%ln::', known))
return set(c.node() for c in foreground)
+def exclusivemarkers(repo, nodes):
+ movemsg = 'obsolete.exclusivemarkers moved to obsutil.exclusivemarkers'
+ repo.ui.deprecwarn(movemsg, '4.3')
+ return obsutil.exclusivemarkers(repo, nodes)
+
def successorssets(repo, initialnode, cache=None):
movemsg = 'obsolete.successorssets moved to obsutil.successorssets'
repo.ui.deprecwarn(movemsg, '4.3')
--- a/mercurial/obsutil.py Tue Jun 27 01:03:01 2017 +0200
+++ b/mercurial/obsutil.py Tue Jun 27 01:11:56 2017 +0200
@@ -35,6 +35,131 @@
else:
stack.append(precnodeid)
+def _filterprunes(markers):
+ """return a set with no prune markers"""
+ return set(m for m in markers if m[1])
+
+def exclusivemarkers(repo, nodes):
+ """set of markers relevant to "nodes" but no other locally-known nodes
+
+ This function compute the set of markers "exclusive" to a locally-known
+ node. This means we walk the markers starting from <nodes> until we reach a
+ locally-known precursors outside of <nodes>. Element of <nodes> with
+ locally-known successors outside of <nodes> are ignored (since their
+ precursors markers are also relevant to these successors).
+
+ For example:
+
+ # (A0 rewritten as A1)
+ #
+ # A0 <-1- A1 # Marker "1" is exclusive to A1
+
+ or
+
+ # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally)
+ #
+ # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1
+
+ or
+
+ # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence))
+ #
+ # <-2- A1 # Marker "2" is exclusive to A0,A1
+ # /
+ # <-1- A0
+ # \
+ # <-3- A2 # Marker "3" is exclusive to A0,A2
+ #
+ # in addition:
+ #
+ # Markers "2,3" are exclusive to A1,A2
+ # Markers "1,2,3" are exclusive to A0,A1,A2
+
+ See test/test-obsolete-bundle-strip.t for more examples.
+
+ An example usage is strip. When stripping a changeset, we also want to
+ strip the markers exclusive to this changeset. Otherwise we would have
+ "dangling"" obsolescence markers from its precursors: Obsolescence markers
+ marking a node as obsolete without any successors available locally.
+
+ As for relevant markers, the prune markers for children will be followed.
+ Of course, they will only be followed if the pruned children is
+ locally-known. Since the prune markers are relevant to the pruned node.
+ However, while prune markers are considered relevant to the parent of the
+ pruned changesets, prune markers for locally-known changeset (with no
+ successors) are considered exclusive to the pruned nodes. This allows
+ to strip the prune markers (with the rest of the exclusive chain) alongside
+ the pruned changesets.
+ """
+ # running on a filtered repository would be dangerous as markers could be
+ # reported as exclusive when they are relevant for other filtered nodes.
+ unfi = repo.unfiltered()
+
+ # shortcut to various useful item
+ nm = unfi.changelog.nodemap
+ precursorsmarkers = unfi.obsstore.precursors
+ successormarkers = unfi.obsstore.successors
+ childrenmarkers = unfi.obsstore.children
+
+ # exclusive markers (return of the function)
+ exclmarkers = set()
+ # we need fast membership testing
+ nodes = set(nodes)
+ # looking for head in the obshistory
+ #
+ # XXX we are ignoring all issues in regard with cycle for now.
+ stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))]
+ stack.sort()
+ # nodes already stacked
+ seennodes = set(stack)
+ while stack:
+ current = stack.pop()
+ # fetch precursors markers
+ markers = list(precursorsmarkers.get(current, ()))
+ # extend the list with prune markers
+ for mark in successormarkers.get(current, ()):
+ if not mark[1]:
+ markers.append(mark)
+ # and markers from children (looking for prune)
+ for mark in childrenmarkers.get(current, ()):
+ if not mark[1]:
+ markers.append(mark)
+ # traverse the markers
+ for mark in markers:
+ if mark in exclmarkers:
+ # markers already selected
+ continue
+
+ # If the markers is about the current node, select it
+ #
+ # (this delay the addition of markers from children)
+ if mark[1] or mark[0] == current:
+ exclmarkers.add(mark)
+
+ # should we keep traversing through the precursors?
+ prec = mark[0]
+
+ # nodes in the stack or already processed
+ if prec in seennodes:
+ continue
+
+ # is this a locally known node ?
+ known = prec in nm
+ # if locally-known and not in the <nodes> set the traversal
+ # stop here.
+ if known and prec not in nodes:
+ continue
+
+ # do not keep going if there are unselected markers pointing to this
+ # nodes. If we end up traversing these unselected markers later the
+ # node will be taken care of at that point.
+ precmarkers = _filterprunes(successormarkers.get(prec))
+ if precmarkers.issubset(exclmarkers):
+ seennodes.add(prec)
+ stack.append(prec)
+
+ return exclmarkers
+
def successorssets(repo, initialnode, cache=None):
"""Return set of all latest successors of initial nodes
--- a/mercurial/repair.py Tue Jun 27 01:03:01 2017 +0200
+++ b/mercurial/repair.py Tue Jun 27 01:11:56 2017 +0200
@@ -20,6 +20,7 @@
error,
exchange,
obsolete,
+ obsutil,
util,
)
@@ -132,7 +133,7 @@
stripobsidx = obsmarkers = ()
if repo.ui.configbool('devel', 'strip-obsmarkers', True):
- obsmarkers = obsolete.exclusivemarkers(repo, stripbases)
+ obsmarkers = obsutil.exclusivemarkers(repo, stripbases)
if obsmarkers:
stripobsidx = [i for i, m in enumerate(repo.obsstore)
if m in obsmarkers]