mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 23:38:50 +03:00
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.
This commit is contained in:
parent
04205af86b
commit
8b519349e8
@ -771,131 +771,6 @@ def makestore(ui, repo):
|
||||
% 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 @@ def getmarkers(repo, nodes=None, exclusive=False):
|
||||
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 @@ def foreground(repo, nodes):
|
||||
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')
|
||||
|
@ -35,6 +35,131 @@ def closestpredecessors(repo, nodeid):
|
||||
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
|
||||
|
||||
|
@ -20,6 +20,7 @@ from . import (
|
||||
error,
|
||||
exchange,
|
||||
obsolete,
|
||||
obsutil,
|
||||
util,
|
||||
)
|
||||
|
||||
@ -132,7 +133,7 @@ def strip(ui, repo, nodelist, backup=True, topic='backup'):
|
||||
|
||||
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]
|
||||
|
Loading…
Reference in New Issue
Block a user