mercurial/obsutil.py
changeset 33143 d09ae850296d
parent 33142 4f49810a1011
child 33144 d0e5bf12f314
equal deleted inserted replaced
33142:4f49810a1011 33143:d09ae850296d
    32 
    32 
    33             if precnodeid in repo:
    33             if precnodeid in repo:
    34                 yield precnodeid
    34                 yield precnodeid
    35             else:
    35             else:
    36                 stack.append(precnodeid)
    36                 stack.append(precnodeid)
       
    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
    37 
   162 
    38 def successorssets(repo, initialnode, cache=None):
   163 def successorssets(repo, initialnode, cache=None):
    39     """Return set of all latest successors of initial nodes
   164     """Return set of all latest successors of initial nodes
    40 
   165 
    41     The successors set of a changeset A are the group of revisions that succeed
   166     The successors set of a changeset A are the group of revisions that succeed